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

Archie's

Well-Known Member
24 Окт 2017
1.936
1.300
113
Учимся создавать скрипты ,анализируя чужие!
Выкладываем в этой теме несложные скрипты ,свои первые наработки (С подробным описанием!!!)
А также задаем вопросы касаемые скриптов (как,что и почему)
 
Последнее редактирование:
PHP:
function ShowChildrenInMCP(tr, is_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 0 or 1))
  reaper.SetTrackStateChunk(tr, tr_chunk_out,true)
end

tr = reaper.GetTrack(0,0)
ShowChildrenInMCP(tr, true)
Select all tracks, Unselect all tracks__________[Archie]
PHP:
--Select all tracks, Unselect all tracks

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

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

reaper.Undo_BeginBlock()--для того, чтобы можно было отменить действие(Ctrl+Z)
  kolichestvo = reaper.CountSelectedTracks( 0 ) --получаем кол-ва выделенных треков (кроме Мастера)
  for i = kolichestvo-1,0,-1 do                     --создаём цикл опроса по каждому выделенному треку (кроме Мастера)
  local track = reaper.GetSelectedTrack(0,i)  --Получаем выбранный трек из проекта
   if  track  then                       --Если трек присутствует
   reaper.DeleteTrack( track )              --удаляем трек
   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)
 
Последнее редактирование:
  • Like
Реакции: Furqat
Интересно. Я думаю, Александр не будет против, если я кое-что выложу из переписок.
Это ох..но интересная информация.
--[[
Все графические ф-и и переменные собраны в таблице 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", 1000, 200, 0, 200, 200
  gfx.init(name,width,height,dockstate,xpos,ypos)
  local fontidx, fontface, fontsz, fontflags = 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.x, gfx.y = 10, 10 -- уст. gfx.x, gfx.y, строки рисуются отталкиваясь от этих координат!
  local info = "Внутри окна нажмите правую, левую кнопку мыши, Alt, Ctrl, Shift, нажмите все одновременно."
  gfx.drawstr(info)
 
 
  -- Иллюстрация -----------------------
  gfx.set(1,0.7,0.4,1) -- цвет, которым будем рисовать иллюстрацию
  -- Текущее значение mouse_cap --
  gfx.x, gfx.y = 10, 80
  gfx.drawstr("mouse_cap = " .. gfx.mouse_cap)
 
  local x, y = 900, 80 -- начальные координаты, рисовать будем справа налево, от младшего к старшим разрядам
  local w, h = 40, 40  -- здесь зададим ширину и высоту квадратиков, соответствующих разрядам
 
  for i = 0, 15, 1 do -- будем идти от нулевого, до 15 разряда. В Lua счет от единицы, но нам здесь удобнее, никто не запрещает!
    gfx.rect(x, y, w, h, 0) -- рисуем квадратик, соотв. разряду
    -- над квадратиком - номер разряда
    gfx.x, gfx.y = x, y - h -- уст. gfx.x, gfx.y
    -- от gfx.x, gfx.y - говорил выше, но...здесь тоже есть возможность выравнивания, опять же, используются флаги!!!
    gfx.drawstr(tostring(i), 5, gfx.x + w, gfx.y + h) -- над квадратиком - номер разряда, flags = 5!
    ------------------------------
    -- вот здесь мы создадим битовую маску
    local Mask = 1<<i -- с помощью сдвига влево("<<") устанавливаем один конкретный бит
    if gfx.mouse_cap&Mask ~= 0 then -- с помощью побитового "И"("&") проверяем, установлен ли этот бит в mouse_cap
      -- в квадратике - значение маски
      gfx.x, gfx.y = x, y
      gfx.drawstr(tostring(Mask), 5, gfx.x + w, gfx.y + h)
    end
    ------------------------------
    x = x - w
  end

end


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

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


--------------------------------------------------
Init() -- Инициализируем окно
mainloop() -- Запускаем осн. луп
[DOUBLEPOST=1514602343][/DOUBLEPOST]Потом я продолжу.
 
  • Like
Реакции: Archie's и dmitryga
Код:
reaper.PreventUIRefresh(1)--замораживаем GUI
  counttracks = reaper.CountTracks(0)    -- даёт значение кол-ва треков
  if counttracks ~= nil then              -- если треков нет, то и ни чего не делать
    for i=1,counttracks  do                --создаём цикл опроса по каждому треку                      
     selecttrack = reaper.GetTrack(0, i-1 ) --получаем объект Трек для каждого порядкового номера трека
     selecttrack = reaper.SetMediaTrackInfo_Value(selecttrack,"I_SELECTED",1)--(выделям трек)Если 1 то выделить,Если 0 снять выделение
    end
  end
reaper.PreventUIRefresh(-1)--размораживаем GUI

Есть ошибки как в синтаксисе, так и в описании и лучше их сразу разобрать и исправить.
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(0, i-1 ) --получаем объект Трек для каждого порядкового номера трека
Получаемый в этой строке объект Медиа Трек не имеет ни какого отношения к select track и называть так объект не правильно! Лучше назвать track или tr.
4. Строка -
PHP:
selecttrack = reaper.SetMediaTrackInfo_Value(selecttrack,"I_SELECTED",1)--(выделям трек)Если 1 то выделить, Если 0 снять выделение
Функции типпа Get отдают значения одного или нескольких параметров, по этому когда мы пишем в цикле -
PHP:
track = reaper.GetTrack(0, i-1 )
мы каждый цикл (каждое 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=1, counttracks  do  -- создаём цикл опроса по каждому треку (кроме Мастера)
  local track = reaper.GetTrack(0, i-1) -- получаем объект Медиа Трек для каждого порядкового номера трека (кроме Мастера)
  reaper.SetMediaTrackInfo_Value(track, "I_SELECTED", 1) -- выделям трек (если 1 то выделить, если 0 снять выделение)
end
В общем, ошибки в каждой строке :)
 
Последнее редактирование:
  • Like
Реакции: vax и Archie's
@Aleksandr Oleynik, я, конечно, пока в этом почти нибумбум, но глядя на этот код, я бы его сократил вообще до трех строк и выкинул совершенно лишние проверки и переменные.
Код:
for i=0, reaper.CountTracks(0)-1 do
  reaper.SetMediaTrackInfo_Value(reaper.GetTrack(0, i), "I_SELECTED", 1)
end
 
@Alex_V,
цикл в LUA начинать с Нуле (i=0) нельзя, хотя это может и работать.
Проверять, есть ли в проекте объект, с которым скрипт должен работать, обязательно нужно, потому как это освободит Рипер от не нужных вычислений - как минимум, а часто - от выдачи скриптом ошибки.
А так - я могу ещё пару вариантов предложить для этого конкретного случая -
PHP:
for i=1, reaper.CountTracks(0) do
  reaper.SetTrackSelected( reaper.GetTrack(0, i-1), 1 )
end
Могу вообще одной строкой предложить записать с тем-же эффектом -
PHP:
reaper.Main_OnCommand(40296,0)

Но тема то называется -
Учимся создавать скрипты ,анализируя чужие!
Учиться нужно начиная с азбуки.
Азбука понятнее, когда она последовательно и понятно изложена.
Нет цели сделать скрипт из меньших строк, есть цель сделать его легко читаемым, чтоб вы потом, когда в скрипте будет 1000 строк, разобрались в нём сами.

И честно говоря, предложенный вами синтаксис споткнётся о первые же более сложные скрипты, когда track, как Медиа Трек нужен будет в десятке функций в цикле.
 
цикл в LUA начинать с Нуле (i=0) нельзя, хотя это может и работать.
Эммм... Это откуда такое? Я вот в документации не нашел ничего подобного: https://www.lua.org/pil/4.3.4.html

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

И честно говоря, предложенный вами синтаксис споткнётся о первые же более сложные скрипты, когда track, как Медиа Трек нужен будет в десятке функций в цикле.
Когда это будет нужно, тогда и надо переменные заводить. Извиняюсь конечно, но в данном случае это просто было создание сущностей (объявление переменных) без должной на то необходимости.
 
Эммм... Это откуда такое? Я вот в документации не нашел ничего подобного
Не знаю, не искал - но ни у кого нет циклов с i=0, да и как-то привычнее понимать, что кол-во чего либо считается с еденицы. Мне более НЕ Удобно то, как это в Рипере сделанно - с нуля.
Это да, это нужно, но в данном случае проверка была лишней. Там просто цикл не будет выполняться, если CountTracks вернет 0.
В данном случаи и во многих других проверка лишняя, но пишешь какой-то скрипт и по ходу -- была лишней, а стала не лишней.
Когда это будет нужно, тогда и надо переменные заводить. Извиняюсь конечно, но в данном случае это просто было создание сущностей (объявление переменных) без должной на то необходимости.
@Alex_V, вы видимо знакомы с програмированием?
А я вот абсолютно не знаком и это не мешает мне писать не примитивные скрипты для себя и для других. И те, кто пытается это делать так-же как и я - тоже програмированием занялись вот прям сейчас, так как в Рипере это полезно.
Так что для учёбы очень хорошо разложить код на мельчайшие составляющие, и я уверен, что код -

PHP:
counttracks = reaper.CountTracks(0)    -- даёт значение кол-ва треков
if counttracks == 0 then return end -- если треков нет, остановить скрипт
  for i=1, counttracks  do                -- создаём цикл опроса по каждому треку
    track = reaper.GetTrack(0, i-1) -- получаем объект Медиа Трек для каждого порядкового номера трека
    reaper.SetMediaTrackInfo_Value(track, "I_SELECTED", 1) -- выделям трек (если 1 то выделить, если 0 снять выделение)
  end
end
на много более понятен новичку, чем то, что написали вы -
PHP:
for i=0, reaper.CountTracks(0)-1 do
  reaper.SetMediaTrackInfo_Value(reaper.GetTrack(0, i), "I_SELECTED", 1)
end
Ваш код даже откоментировать крайне тяжело.
 
Последнее редактирование:
Не знаю, не искал - но ни у кого нет циклов с i=0, да и как-то привычнее понимать, что кол-во чего либо считается с еденицы. Мне более НЕ Удобно то, как это в Рипере сделанно - с нуля.
Ну, в Lua индексация массивов обычно - с единицы (но, в принципе, может быть с любого индекса). Поэтому, думается, и перебор индексов делают чаще с 1. Почему в Рипере индексы с нуля, это как раз понятно. Он написан на C, а там индексация с нуля. В большинстве языков программирования ровно точно так же. На деле это во многом удобнее.
 
  • Like
Реакции: Morpheus
PHP:
reaper.PreventUIRefresh(1)--замораживаем GUI
reaper.Undo_BeginBlock() --для того, чтобы можно было отменить действие (Ctrl+Z)

for i=1,reaper.CountSelectedTracks (0) do      --создаём цикл опроса по каждому выделенному треку (кроме Мастера)
  tr = reaper.GetSelectedTrack( 0, 0 )           --получаем выбранный трек из проекта (кроме Мастера)
  reaper.SetMediaTrackInfo_Value(tr,"I_SELECTED",0)--Снимаем выделения
end
kol_vo = reaper.CountTracks( 0 )          -- даёт значение кол-ва треков в проекте (кроме Мастера)
if kol_vo == 0 then  return end            -- если треков нет, остановить скрипт
  for i = 1,kol_vo do                       --создаём цикл опроса по каждому треку в проекте (кроме Мастера)
   track = reaper.GetTrack(0,i-1)            --получаем Трек для каждого порядкового номера трека
   item = reaper.CountTrackMediaItems( track )--подсчитать количество item в треке
     if item == 0 then                         --если item нет, то 
      reaper.SetMediaTrackInfo_Value( track, "I_SELECTED", 1 )-- выделям трек
     end
  end
for i = 1,reaper.CountSelectedTracks( 0 ) do   --создаём цикл опроса по каждому выделенному треку (кроме Мастера)
 local track = reaper.GetSelectedTrack( 0, 0 )  --получаем выбранный трек из проекта (кроме Мастера)   
 track = reaper.DeleteTrack( track )             --удаляем трэк
end   
reaper.Undo_EndBlock("Remove all tracks with no items",1) --завершаем действие отменить действие(Ctrl+Z)     
reaper.PreventUIRefresh(-1)--размораживаем GUI
 
@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. Цикл по трекам - в обратную сторону, от последнего к первому, для того, чтобы не получалось так, что обращаемся по индексу к треку, который уже удалили
 
Почему в Рипере индексы с нуля, это как раз понятно. Он написан на C, а там индексация с нуля. В большинстве языков программирования ровно точно так же. На деле это во многом удобнее.
Я же написал - я не програмист от слова ВООБЩЕ, по этому мне с еденицы понятнее :)
 
Я же написал - я не програмист от слова ВООБЩЕ, по этому мне с еденицы понятнее
Ну а я всего лишь попытался объяснить, откуда ноги растут. Вот и все. :) На самом деле, если лезть в программирование, то надо понимать, что там, как правило (с некоторыми исключениями), все индексируется с нуля. Но надо быть готовым к индексации любого вида.
 
  • Like
Реакции: Aleksandr Oleynik
@Alex_V, идея с обратным отсчётом в цикле крутая своей простотой - браво!
С точки зрения обучения, позволю себе ещё один вариант, возможно более понятный -

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

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

Не смотря на то, что ваш вариант не сильно оптимален для решения поставленной задачи, что хорошо продемонстрировал своим кодом @Alex_V, я пройдусь всё же
по ошибкам -
PHP:
kol_vo = reaper.CountTracks( 0 )
item = reaper.CountTrackMediaItems( track )
это функции отдающие кол-во, и если в первой функции вы конечно могли параметр назвать kol_vo, хотя потом сами будете вспоминать чего же это кол-во,
то во второй item - всегда называют объект, а ни как не его кол-во!!!
Т.е. лучше называть -
counttrack
countitem
Дальше ошибка, которую вы уже делали и я вас поправил -
функция - reaper.DeleteTrack( track ) функция из той-же серии Set - т.е. функция действия и писать -
track = reaper.DeleteTrack( track ) нельзя и бессмысленно, так как track у вас тут быдет всегда получать значение true - т.е. подтверждение выполнения и больше ни чего,
но если бы в коде дальше была бы функция, в которой нужно было бы с треком ещё что-то делать, то скрипт бы ваш НЕ РАБОТАЛ, так как вы полученный
функцией track = reaper.GetTrack(0,i-1) Медиа Трек затёрли бы значением true.
 
С точки зрения обучения, позволю себе ещё один вариант, более классический
С точки зрения обучения изменять счетчик цикла внутри тела цикла - моветон. В некоторых компилируемых языках такое даже не компилируется.
 
С точки зрения обучения изменять счетчик цикла внутри тела цикла - моветон. В некоторых компилируемых языках такое даже не компилируется.
Отлично - прислушаюсь к мнению программиста и делать этого впредь не стану, собственно и не делал ни когда - не было необходимости!
А вот проход цикла в обратном направлении уже несколько раз был нужен и я тут по горячим следам, благодаря вам, в текущей своей работе поменял вот этот вот код -
PHP:
    index_k = 0
    if IndexUp < IndexDown then
      for i=1, #RegionName do
        if RegionName[i].Index > IndexUp and i <= 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 i <= IndexDown then
          RegionName[i].SongName = RegionName[i-1].SongName
        end
      end
      RegionName[IndexUp].SongName = SongNameDown
    end
(Теперь же это стало красиво, без лишних глобальных переменных :))

Делаю свой первый скрипт с GUI, у Жени (@EUGEN27771) вот учусь.
Нужно было сделать визуализацию (и перезапись в таблице) перетаскивания композиции с большим порядковым номером на меньший со сдвижкой всех композиций в очереди.
И та-же фигня - поскольку перезапись происходит верхнего по рангу элемента в нижний, при классическом цикле первым затирался верхний и брать данные уже было негде, во всяком случаи за один цикл сделать это можно было вот только ТАК - пройдясь по циклу в обратном порядке.
GUI TEST 8.gif
 
Последнее редактирование:
С точки зрения обучения изменять счетчик цикла внутри тела цикла - моветон. В некоторых компилируемых языках такое даже не компилируется.
Я чуть ещё подумал - а я ведь там не меняю счётчик цикла, он как отсчитывал от i=1 до reaper.CountTracks(0), так и отсчитывает.
Я там меняю в цикле индекс трека, смещая его на кол-во удалённых треков.
Я ведь мог и не перезаписывать i в цикле, а написать новую переменную - y = i-c например, и брать Медиа Трек по y, а не по i
 
Последнее редактирование:
Я ведь мог и не перезаписывать i в цикле, а написать новую переменную - y = i-c например, и брать Медиа Трек по y, а не по i
Можно так, а можно и цикл другого типа - не со счетчиком, а while (работать будет слегка медленнее). Но цикл от конца в начало списка получается проще для понимания и в реализации. Тут главное - понять проблему, которая возникает при удалении элементов, если идти по списку от начала и при этом удалять из него элементы.
 
Цикл всегда с нуля. Это в луа с единицы
Но тогда вся система исчислений должна начинаться с нуля.
Иначе получается бред - функция подсчёта кол-ва треков выдает число 3 и это значит что треков ТРИ, а не ЧЕТЫРЕ, как если бы исчисление начиналось с нуля.
Да и с нулём и в других местах не всё в порядке -
В документации по LUA написанно, что nil - это ноль, тогда почему функции подсчёта треков, айтемов, FX-ов, если ИХ нет совсем выдают НОЛЬ, а не nil и если в выражениях, использующих эти данные написать не НОЛЬ, а nil - они работать не будут.
Мне лично было бы понятнее и логичнее, если бы НОЛЬ это действительно был nil - ничего, т.е. отсутствие.

Но с другой стороны, я уже понимаю отличие nil от нуля - nil это как бы вообще ни чего не заданно, свободная ячейка памяти у параметра....., а НОЛЬ, это уже какие то данные.
 
Последнее редактирование:
@Aleksandr Oleynik, потому что по умолчанию целочисленным переменным присваивается ноль. А nil - это, по-моему, тип данных.
UPD: ну да - я был прав: https://www.lua.org/pil/2.1.html
Не может же переменная одного типа принять значение другого типа или может? А, Александр?
 
Не до конца понимаю что такое тип данных и к какому типу относится nil, но переменной, которая было равна НУЛЮ, я запросто значение nil могу присвоить.
 
Но тогда вся система исчислений должна начинаться с нуля.
Иначе получается бред - функция подсчёта кол-ва треков выдает число 3 и это значит что треков ТРИ, а не ЧЕТЫРЕ, как если бы исчисление начиналось с нуля.
Нет, не должна. Не надо путать количество элементов, номер элемента в списке и его индекс. Количество элементов в списке, если он не пуст, больше нуля. Индекс элемента в списке - это не его порядковый номер, это способ адресации элементов. Это, кстати, может вообще не числом быть (в ассоциативном массиве, например).

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

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

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