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

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

  1. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    Ребята, есть ли возможность (при поможи какой-то функции) как-то остановить или выйти из defer()?
     
  2. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    @Rsay, условие выхода написать.
     
  3. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    @Aleksandr Oleynik, можете пожалуйста пример кода показать? я не понимаю по какой команде он завершается....

    Методом тыка пока дошел до такого, но пока рано не все гладко:
    У меня есть графический интерфейс - СКРИПТ, который reaper.defer(СКРИПТ) крутит по кругу и по нажатию на ESC запускается gfx.quit() и reaper.atexit(СКРИПТ)... Окно закрывается. но скрипт продолжает выполнятся...
     
  4. @Michael

    @Michael Well-Known Member

    Регистрация:
    14 дек 2010
    Сообщения:
    776
    Симпатии:
    1.179
    Пол:
    Мужской
    Адрес:
    Орёл / Москва
    Код:
    if gfx.getchar() >= 0 and gfx.getchar() ~= 27 then reaper.defer(СКРИПТ) else reaper.atexit(gfx.quit) end 
     
    Aleksandr Oleynik нравится это.
  5. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    253
    Симпатии:
    58
    Пол:
    Мужской
    Подскажите есть ли возможность заставить defer() работать медленнее ?
    Например: Отработал defer один цикл ,подождал 1 или 2 сек. пошёл на второй круг и т.д.
    Ну и не только дефер
    Есть ли в API что то типа экшена Action: Wait 1 second before next action так как экшен в скрипте не работает
     
    Последнее редактирование: 17 апр 2018
  6. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
  7. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    253
    Симпатии:
    58
    Пол:
    Мужской
  8. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    @Archchie, как вариант
    forum.cockos.com/archive/index.php/t-168270.html
    но было бы неплохо узнать есть ли удобнее)
     
    Archchie нравится это.
  9. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    253
    Симпатии:
    58
    Пол:
    Мужской
    @Rsay, Спасибо!
     
  10. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    Чуть позже напишу... на iPadе пока
     
  11. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    PHP:
    defer_rate 1

    cycle 
    0
    function mainloop ()
      
    cycle cycle+1
      
    if cycle == defer_rate then
        main
    ()
        
    cycle 0
      end

      
    if TEST_Env then
        char 
    gfx.getchar()
        if 
    char~=-1 then reaper.defer(mainloopend --defer
        gfx
    .update() -- Update gfx window
      
    else
        
    reaper.defer(mainloop)
      
    end
    end
     
    Archchie нравится это.
  12. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    Это вырванно из скрипта и не есть универсальной функцией, но смысл понятен -
    Дефер запускает по циклу промежуточную функцию - счетчик, и можно, задавая defer_rate, менять скорость перезапуска функции main()
     
  13. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    Спасибо, @@Michael, только он (дефер) все равно работает вроде...
    Я поставил консоль для теста: оно закрывается, а в консоли продолжают изменятся значения, даже если закрыть проект и открыть новый
     
    Последнее редактирование: 23 апр 2018
  14. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    Ребята, а можно как-то удалить точку автоматизации ссылаясь на ее номер?
    И еще как можно функционально узнать в каких единицах измеряется данный трек автоматизации (к примеру верхняя и нижняя точки)
     
    Последнее редактирование: 24 апр 2018
  15. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    Можно.
    Узнать её time и удалить по PointRange.
    А оно всегда от 0 до 1, на сколько помню.
     
  16. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    @Aleksandr Oleynik, ну это по времени, это я умею.. Мне нужно по номеру))

    Про автоматизацию, то я немного поколупался, нашел как узнать крайние значения и уже думал, что сделал то, что нужно, но набрел на кучу подводных камней, которые сложно контролировать:
    Там есть много вариантов от 0 до 1 это наверное только стандартные, а ля громкость и тп... И при том что соотношение редактируемых параметров другое: громкость в дБ, от бесконечности до 0 (смотря как в настройках), панораме тоже заморочки от 100Л до 100Р, и это все в коде регулируется от 0 до 1... Единственное что мьютирование легко реализируется=))

    В РеаконтролМИДИ уже другая систем - либо в тисячах либо как велосити от 0 до 127 (если в настройках РеаконтролМиди поменять), а если не поменять то будет тысячами как питч (из того же РеаконтролМиди)...

    Внешние плагины в зависимости от параметра автоматизируемой ручки
    Одним словом жуть...
     
  17. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    @Rsay, берете номер точки, узнаёте её время и дальше по времени.
     
  18. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    Привет, ребята! Можно как-то отследить уровень дБ на аудио айтеме?
    Задача удалить хвост (только хвост) когда он нижу определенного уровня (к примеру -24 дБ)
    Стандартный удалятель тишины не сильно подходит, т.к. он показывает оно, да и еще некоторые штучки есть
     
  19. x.com

    x.com И это тоже не я :)

    Регистрация:
    13 авг 2007
    Сообщения:
    917
    Симпатии:
    223
    Пол:
    Мужской
    Адрес:
    Приморский Край
    @Rsay, Первое что пришло в голову fade-in, fade-out. Когда приходит "ОНО", со своими ШТУЧКАМИ, я НИЖУ плинтуса сразу, трешхолдит не по децки (минус 24 дБ минимум).
     
  20. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    Можно, но задачка не из тривиальных.
    Женя мне делал Функцию, которая складывала точки в которых уровень сигнала в айтеме ниже заданного и выше заданного.
    Очень не просто её даже вычленить из моего скрипта для другой задачи.

    А так то -
    GetMediaItemTake_Peaks
    а дальше - мрак

    Вот часть кода формирующего таблицы -
    PHP:
    attThresh_dB = -65  -- уровень Wav кривой выше которого скрипт включает Fx OnOff
    relThresh_dB 
    = -60  -- уровень Wav кривой ниже которого скрипт выключает Fx OnOff

    function GetAudioItemTrigPoints(item)
      
    local take reaper.GetActiveTake(item)
      
    take reaper.GetActiveTake(item)
      if 
    not take then return {}   -- пока пустая таблица
      
    elseif reaper.TakeIsMIDI(takethen return GetMIDIItemTrigPoints(itemtake)
      
    end
      local item_start 
    reaper.GetMediaItemInfo_Value(item"D_POSITION")
      
    local item_len reaper.GetMediaItemInfo_Value(item"D_LENGTH")
      ------------------
      
    local starttimen_chansn_splswant_extra_typebufretval
      n_chans 
    1         -- GetPeaks only 1 channel now!!!
      
    n_spls math.ceil(item_len*peakrate) -- Noteits Peak Samples!
      
    want_extra_type -- get minmaxno spectral
      buf 
    reaper.new_array(n_spls n_chans 2) -- maxminonly for 1 channel
      buf
    .clear()         -- Clear buffer
      retval 
    reaper.GetMediaItemTake_Peaks(takepeakrateitem_startn_chansn_splswant_extra_typebuf)
      ------------------
      
    local attThresh  10^(attThresh_dB/20)
      
    local relThresh  10^(relThresh_dB/20)
      
    local trig_points = {}
      
    local last_trig false
      
    for 1n_spls do
        
    local max_peak math.max(math.abs(buf[i]), math.abs(buf[i+n_spls]))
        if 
    not last_trig and max_peak >= attThresh then
          trig_points
    [#trig_points+1] = {item_start + (i-1)/peakrate, true}; last_trig = true
        
    elseif last_trig and max_peak relThresh then
          trig_points
    [#trig_points+1] = {item_start + (i-1)/peakrate, false}; last_trig = false
        
    end
      end
      
    ------------------
      if 
    #trig_points > 0 then
        
    if trig_points[1][2] ~= false then  -- Start всегда falseначало айтема
          table
    .insert(trig_points1, {item_startfalse})
        
    end
        
    if trig_points[#trig_points][2] ~= false then  -- End всегда false, конец айтема
          
    table.insert(trig_points, {item_start item_lenfalse})
        
    end
      end
      
    ------------------
      return 
    trig_points
    end

    local items_trig 
    = {} -- Таблица тригточек для айтемов
      local item_cnt 
    reaper.CountTrackMediaItems(track)
      for 
    1item_cnt do
        
    local item reaper.GetTrackMediaItem(tracki-1)
        
    items_trig[i] = GetAudioItemTrigPoints(item)
      
    end

     
    Последнее редактирование: 4 май 2018
  21. incubator

    incubator Active Member

    Регистрация:
    24 янв 2007
    Сообщения:
    311
    Симпатии:
    87
    Адрес:
    Spb
    Подскажите пожалуйста как создать код что бы железно было без анду точки? Потому когда настройки такие

    [​IMG]

    он создает кучу точек. Код сделал как учили, но чего то не помогает
    Код стоит на клике мышкой

    Код:
    function click()
    reaper.PreventUIRefresh(1)
    
    reaper.Main_OnCommand(40635, 0) ---Time selection: Remove time selection
    
    reaper.Main_OnCommand(reaper.NamedCommandLookup('_SWS_UNSELALL'), 0) ----SWS: Unselect all items/tracks/env points
    
    
    reaper.Main_OnCommand(40513, 0)--View: Move edit cursor to mouse cursor
    
    reaper.PreventUIRefresh(-1)
    
    end
    
    reaper.defer(click)
     
  22. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    253
    Симпатии:
    58
    Пол:
    Мужской
    @incubator,
    С одной Undo точкой
    PHP:
    function click()

        
    reaper.Undo_BeginBlock()
        
    reaper.PreventUIRefresh(1)

        
    reaper.Main_OnCommand(406350) ---Time selectionRemove time selection

        reaper
    .Main_OnCommand(reaper.NamedCommandLookup('_SWS_UNSELALL'), 0) ----SWSUnselect all items/tracks/env points

        reaper
    .Main_OnCommand(405130)--ViewMove edit cursor to mouse cursor

        reaper
    .PreventUIRefresh(-1)
        
    reaper.Undo_EndBlock("name_script",1)

    end
    click
    ()


    Без Undo точек: / Deselect All 'move play cursor under mouse cursor[no undo]
    PHP:


        
    -----------------------------------------------------------------------------
        
    local function No_Undo()endlocal function no_undo()reaper.defer(No_Undo)end
        
    -----------------------------------------------------------------------------


        
    reaper.GetSet_LoopTimeRange1000)

        
    local windowsegmentdetails reaper.BR_GetMouseCursorContext()
        
    local mouse reaper.BR_GetMouseCursorContext_Position()
        if 
    mouse 0 then
            reaper
    .SetEditCurPosmouse 0)
        
    end

        local count_track 
    reaper.CountTracks()
        if 
    count_track == 0 then
             no_undo
    ()
           return
        
    end


        reaper
    .PreventUIRefresh(1)

        for 
    1,count_track do

            
    local tr reaper.GetTrack(0,i-1)
            
    reaper.SetTrackSelectedtr)
      
            
    local count_tr_item reaper.CountTrackMediaItemstr )
            for 
    i2 1,count_tr_item do
                
    local tr_item reaper.GetTrackMediaItemtri2-)
                
    reaper.SetMediaItemSelectedtr_item)
            
    end
            local count_track_env 
    =  reaper.CountTrackEnvelopestr )
            for 
    i2 1,count_track_env do
                
    local track_env reaper.GetTrackEnvelopetr i2-)
                
    local count_Env_Point reaper.CountEnvelopePointstrack_env )
                for 
    i3 1,count_Env_Point do
                    
    reaper.SetEnvelopePointtrack_envi3-1____0)
                
    end
                local count_automat_item 
    reaper.CountAutomationItemstrack_env )
                for 
    i3 1,count_automat_item do
                    
    reaper.GetSetAutomationItemInfotrack_envi3-1'D_UISEL'0)
                
    end
            end
        end

        reaper
    .PreventUIRefresh(-1)
        
    reaper.UpdateArrange()
        
    no_undo()

     
    Последнее редактирование: 10 май 2018
  23. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    @Aleksandr Oleynik, спасибо, да, код еще тот=)) Попробую тогда обойти чем-то....
     
  24. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    Как можно обойти? Вам по сути нужен Гейт!
     
  25. Rsay

    Rsay New Member

    Регистрация:
    27 окт 2017
    Сообщения:
    24
    Симпатии:
    2
    Пол:
    Мужской
    @Aleksandr Oleynik, пришлось научится удалять лишнее в хвоте с помощью удалятеля тишины, но это пока так себе вариант, не во всех случаях что мне надо работает, да и окно выскакивает и настройки менять не особо можно
     
  26. incubator

    incubator Active Member

    Регистрация:
    24 янв 2007
    Сообщения:
    311
    Симпатии:
    87
    Адрес:
    Spb
    @Archchie, Спасибо большое всегда помогаете мне!
     
  27. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    253
    Симпатии:
    58
    Пол:
    Мужской
    Нарисовал вот такую кнопочку:
    PHP:
        local function msg(param);reaper.ShowConsoleMsg(param.."\n")end   -- msg('test')
        --------------------------------------------------------------------------------



            
    xOut yOut reaper.GetMousePosition()  xOut yOut xOut-230yOut-125                      
            header 
    = [=[test test test]=]
            
    gfx.clear 4210752
            gfx
    .init(header,350 105,0,xOutyOut  )
            ---

        function 
    main(numb)

            
    gfx.setfont(1,"Verdana",15,117) --установить Шрифты
            gfx
    .set(0,0.75,0.75,1) -- r,g,b,aустанавливаем цветкоторым будем рисовать info
            gfx
    .xgfx.2518 -- устgfx.xgfx.yстроки рисуются отталкиваясь от этих координат!
            
    gfx.drawstr([=[NO SELECTED MEDIA ITEM in TIME SELECTION !]=])
            
    gfx.setfont(1,"Verdana",15,105) --установить Шрифты
            gfx
    .xgfx.10040
            gfx
    .drawstr([=[Select an item in time selection ]=])  
            ---

            
    local button numb -- = 0  

            gfx
    .set(0.4,0.4,0.4,1) -- r,g,b,aустанавливаем цветкоторым будем рисовать info        
            gfx
    .roundrect(11565100304)--Рисует прямоугольник с закругленными углами.
      
            if 
    button == 1 then        
                gfx
    .gradrect(117,67,97,270.2,0.2,0.2,1)--Заполняет прямоугольник градиента указанным цветом и альфой(x,y,w,hr,g,b,a)
            elseif 
    button == 0 then
                gfx
    .gradrect(117,67,97,270.3,0.3,0.3,1)--Заполняет прямоугольник градиента указанным цветом и альфой(x,y,w,hr,g,b,a)
            
    end
      

            gfx
    .line(213,93,117,67 )
            
    gfx.line(213,67,117,93 )
            
    gfx.roundrect(1196992224)----Рисует прямоугольник с закругленными углами.
      
            if 
    button == 1 then
                gfx
    .gradrect(119,69,92,220.5,0.5,0.5,1)--Заполняет прямоугольник градиента указанным цветом и альфой(x,y,w,hr,g,b,a)
            elseif 
    button == 0 then
                gfx
    .gradrect(119,69,92,220.4,0.4,0.4,1)--Заполняет прямоугольник градиента указанным цветом и альфой(x,y,w,hr,g,b,a)
            
    end
            
    ---
      
            
    gfx.xgfx.15671 -- устgfx.xgfx.yстроки рисуются отталкиваясь от этих координат!
            
    x,gfx.xgfx.y--устgfx.xgfx.y,строки рисуются отталкиваясь от этих координат!
            
    gfx.setfont(1,"Verdana",18,105) --установить Шрифты
      
            
    if button == 1 then
                gfx
    .set(0000.3)-- r,g,b,aустанавливаем цветкоторым будем рисовать info
            
    elseif button == 0 then
                gfx
    .set(0000.7)-- r,g,b,aустанавливаем цветкоторым будем рисовать info
            end
            
    for 1do
              
    gfx.xgfx.iy-i
              gfx
    .drawstr("OK")
            
    end
      
            gfx
    .set(0.8,0.8,0.8,0.9) -- r,g,b,aустанавливаем цветкоторым будем рисовать info
            gfx
    .xgfx.x,y
            gfx
    .drawstr("OK")

        
    end
        
    ---


        ----------------
        function 
    Mouse_Is_Inside(xywh) --мышь находится внутри
            local mouse_x
    mouse_y gfx.mouse_xgfx.mouse_y
            local inside 
    =
            
    mouse_x >= and mouse_x < (w) and
            
    mouse_y >= and mouse_y < (h)
            return 
    inside
        end
        
    -----------------



        function 
    loop()

            -- If 
    the left button is down
            
    if gfx.mouse_cap&== 1  then
                
    -- If the cursor is inside the rectangle AND the button wasn't down before
                if Mouse_Is_Inside(117,70,98,23) and not mouse_btn_down then
                    main(1)
                    mouse_btn_down = true
                    state = 1
                end
            -- If the left button is up
            else
                main(0)
                mouse_btn_down = false
            end
      
            if gfx.mouse_cap&1 == 0 and  Mouse_Is_Inside(117,70,98,23) and state == 1 then gfx.quit() end
            if not Mouse_Is_Inside(117,70,98,23) then state = 0 end
            if gfx.getchar() >= 0 then reaper.defer(loop)else reaper.atexit(gfx.quit) end
            gfx.update()
      
        end

        loop()
    И подскажите пожалуйста как заставить её взаимодействовать со скриптом ? Что бы она работала как функция reaper.MB('','',0)
    например: вот на таком примере
    PHP:
        local STOP_Script;
        
    local function example()
      
            
    local start_Loop End_Loop reaper.GetSet_LoopTimeRange0000)
            if 
    start_Loop ~= End_Loop then

                local count_item 
    reaper.CountSelectedMediaItems)
                for 
    1,count_item do
                    
    local item reaper.GetSelectedMediaItem0i-)
                    
    local position reaper.GetMediaItemInfo_Valueitem'D_POSITION' )
                    
    local length reaper.GetMediaItemInfo_Valueitem'D_LENGTH' )
                    
    local item_end position length
                    
    if position End_Loop and item_end start_Loop then
                        LoopTime_sel_item 
    1
                      
    break
                    
    end
                end
                
    if not LoopTime_sel_item then
                    local MB 
    reaper.MB([=[  NO SELECTED MEDIA ITEM in TIME SELECTION !
      
     ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
                            Select an item in time selection
                             ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ 
    ]=],
                              
    ' example  ',0)
                    
    STOP_Script 1
                    
    if MB == 1 then return end
                      
                
    else
                    for 
    count_item-1,0,-do
                        
    local item reaper.GetSelectedMediaItem0)
                        
    local position reaper.GetMediaItemInfo_Valueitem'D_POSITION' )
                        
    local length reaper.GetMediaItemInfo_Valueitem'D_LENGTH' )
                        if 
    position End_Loop or position+length start_Loop then
                            reaper
    .SetMediaItemSelecteditem)
                        
    end
                    end
                end
            end
        end
        example
    ()
        
    reaper.UpdateArrange()
     
    Последнее редактирование: 10 май 2018
  28. Archchie

    Archchie Active Member

    Регистрация:
    24 окт 2017
    Сообщения:
    253
    Симпатии:
    58
    Пол:
    Мужской
    Ни это ?
    reaper.ApplyNudge( project, nudgeflag, nudgewhat, nudgeunits, value, reverse, copies )
    -- только эта функция работает для всех выделенных айтемов

    или
    обновил 2-й раз 14:22 мск. 16.05.18.
    Предыдущая не правильно работала с растянутым play-rate:
    PHP:

    правый край

    reaper
    .SetMediaItemLengthitemlengthtrue )

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

    левый край

      local 
    function SetMediaItemLeftTrim(value,item)
        
    local Pos reaper.GetMediaItemInfo_Valueitem'D_POSITION' )
        
    local len reaper.GetMediaItemInfo_Valueitem'D_LENGTH' )
        
    local take reaper.GetActiveTakeitem )
        
    local playrate reaper.GetMediaItemTakeInfo_Valuetake'D_PLAYRATE')
        
    local offset reaper.GetMediaItemTakeInfo_Valuetake'D_STARTOFFS' )
        if 
    len value then
          reaper
    .SetMediaItemLengthitem,  value true )
          
    reaper.SetMediaItemPositionitem,(len-value)+ Postrue )
          
    reaper.SetMediaItemTakeInfo_Valuetake'D_STARTOFFS',offset + (len-value)*playrate )
        else
          if 
    Pos < (value-lenthen return end
          reaper
    .SetMediaItemLengthitemvalue true )
          
    reaper.SetMediaItemPositionitemPos-(value-len), true )
          
    reaper.SetMediaItemTakeInfo_Valuetake'D_STARTOFFS',offset + (len-value)*playrate )
        
    end
      end

     
    Последнее редактирование: 17 май 2018
    Aleksandr Oleynik нравится это.
  29. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    @Archchie, спасибо огромное!
    Очень не хотелось разбираться с офсетом, вы выручили :)
     
  30. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    А никто не знает, где поискать алгоритм для поиска loop points?
    Я тут пытаюсь немного автоматизировать процес нарезки сэмплов. И самый ад, конечно, происходит при нарезке сустейнов.
    В общем и целом концепция очень простая:
    • вычленяем "чистый" фрагмент сустейна (это лучше делать "человеком")
    • режем в произвольной точке
    • меняем местами начало и конец
    • и делаем так.
    2018-05-25_03-24-40.png

    Но если сделать "просто" так, в лучшем случае будет тембральный, и, наверняка, динамический контраст.
    А в худшем, и это не редкость, а, скорее, очень частая напасть, попадаешь в противофазу, да так, что найти фазу, в силу "живости" источника - та еще задачка.

    Вот идеально с этой задачей, КМК, справляется sample robot. Но он, к сожалению, работает только на стерео, что в нашу много-микрофонную бытность не комильфо.
    Гуглинг засран простыми howto для обыкновенных лупов (драмсы, гитарные рифы), а найти что-то стоящее по закольцовке сэмплов я чет не могу.

    Набрел на такую тему https://forum.cockos.com/showthread.php?t=180087

    Но, во-первых, это слишком жирно, учитывая 6+ исходных треков для каждого сэмпла. А во-вторых, мне кажется, кардинально от моего способа это дело не отличается, все равно точно также можно нарваться на противофазу.
    Есть идеи?
     
  31. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    попробовал начать с самого очевидного: поиска одинаковых сэмплов в тейке:
    Код:
    def find_loop(take, search_area):
        accessor = RPR_CreateTakeAudioAccessor(take)
        start = RPR_GetAudioAccessorStartTime(accessor)
        end = RPR_GetAudioAccessorEndTime(accessor)
        sample_length_sec = RPR_parse_timestr_len(search_area, 0, 4)
        end -= sample_length_sec
    
        ret = int()
        start_buf = list([0] * 2 * search_area)
        end_buf = list([0] * 2 * search_area)
    
        (ret, start_buf) = RPR_GetAudioAccessorSamples(
            accessor, 44100, 2, start, search_area, start_buf)
        if ret == 1:
            pr('is audio\n')
    
        if ret == 0:
            pr('is not audio\n')
        if ret == -1:
            pr('error\n')
        (ret, end_buf) = RPR_GetAudioAccessorSamples(
            accessor, 44100, 2, end, search_area, end_buf)
    
        # pr('start buffer: %s \n' % start_buf)
    
        points = get_loop_points(start_buf, end_buf, search_area, 5)
    
        start += RPR_parse_timestr_len(points[0], 0, 4)
        end += RPR_parse_timestr_len(points[1], 0, 4)
        pr('start: %s, end: %s\n' % (start, end))
        return (start, end)
    
    
    def get_loop_points(start_buf, end_buf, search_area, presigion):
        starts = list()
        ends = list()
        for idx in range(search_area // 2):
            starts.append(sample_from_index(start_buf, idx, presigion))
            ends.append(sample_from_index(end_buf, idx, presigion))
    
        # pr('\n')
        # pr('starts: %s' % starts)
        # pr('\n')
        # pr('ends: %s' % ends)
        # pr('\n')
        for idx, val in enumerate(starts):
            if val in ends:
                pr(val)
                start = idx
                end = ends.index(val)
                pr('\n')
                return (start, end)
    
    
    def sample_from_index(buf, idx, presigion):
        sample1 = buf[idx * 2]
        sample2 = buf[idx * 2 + 1]
        sample1 = int(float(sample1) * 100000) / 100000
        sample2 = int(float(sample2) * 100000) / 100000
        return (sample1, sample2)
    
    И вывод в консоль вполне себе обнадеживающий:
    Код:
    is audio
    (0.00414, -0.00149)
    start: 0.004854166666666666, end: 1.0648958333333367
    (0.004854166666666666, 1.0648958333333367)
    Но вот когда я пытаюсь обрезать руками итем по полученным временным отметкам, получается, что сэмплы-то нифига не одинаковые...
    2018-05-25_08-58-10.png
    --- добавлено 25 май 2018 в 03:04 ---
    вообще идея следющая: найти в указанном тайи-селекшн две точки, в которых сэмплы максимально близки по значению друг с другом, а потом дополнить условие окном, в котором сравниваются близлешайшие отрезки в одном направлении с меньшим разрешением (допустимой погрешностью)
     
  32. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    @PianoIst, честно говоря задачу до конца так и не понял :(
    Пиковые, или любые другие значения уровней, ни как не характеризуют одинаковость сэмплов. Тебе прийдется сравнивать посэмплово.
     
  33. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    @Aleksandr Oleynik, задача - сделать бесшовный сустейн луп. Грубо говоря (и это самый проблемный вариант), синус режем, перемещаем как в посте выше, и получаем каку.
    Сэмпл я имел ввиду именно точки уровней, которые 44100 в секунду. Вот мне и интересно, почему когда я нахожу время, на котором они одинаковые (дальше уже можно будет усложнять задачу матчинга), и я верю, что нахожу, но режу неправильно(
    --- добавлено 25 май 2018 в 07:07 ---
    Как вообще посэмплово по аудио-ацессору передвигаться? Может я в секунды плохо конвертирую?
     
  34. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    так, судя по всему, точки я нахожу правильно, но что-то происходит при конвертации в секунды. Потому что стоит чуть-чуть подвинуть конец вперед, и все срастается
     
  35. Aleksandr Oleynik

    Aleksandr Oleynik Well-Known Member

    Регистрация:
    16 янв 2007
    Сообщения:
    15.532
    Симпатии:
    8.063
    Пол:
    Мужской
    Адрес:
    Киев
    @PianoIst, тебе Женя нужен - он на этом собаку съел :)
    AudioAccessor - его любимая функция!
     
    Последнее редактирование: 25 май 2018 в 08:54
    PianoIst нравится это.
  36. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    от, видимо, где собака порылась
    https://github.com/ReaTeam/ReaScripts-Templates/blob/master/Audio/Working with audio samples.lua
    Код:
    -- Loop through the audio, one block at a time
        local starttime_sec = range_start
        for cur_block = 0, n_blocks do
    
            -- The last iteration will almost never be a full block
            if cur_block == n_blocks then block_size = extra_spls end
           
            samplebuffer.clear()   
           
            -- Loads 'samplebuffer' with the next block
    GetSamples(audio, samplerate, n_channels, starttime_sec, block_size, samplebuffer)
    объясните мне строчку
    Код:
     -- The last iteration will almost never be a full block
            if cur_block == n_blocks then block_size = extra_spls end
    что такое then?)
    Получается, что "дешево" взять конкретную точку с конца нельзя, если я правильно понял. Надо, как с доступом к файлу - читать все
    --- добавлено 25 май 2018 в 10:39 ---
    а, не, вотоно:)
    Код:
    starttime_sec = starttime_sec + ((block_size * n_channels) / samplerate)
    Кароч, я где-то что-то просто пропустил, ща попробуем этот способ)
     
  37. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    о, чего словил:
    Код:
    ---------------------------
    Microsoft Visual C++ Runtime Library
    ---------------------------
    Runtime Error!
    
    Program: C:\Program Files\REAPER (x64)\reaper.exe
    
    R6025
    
    - pure virtual function call
    
    
    ---------------------------
    ОК 
    ---------------------------
    
    Делал объектный вариант Жениного скрипта для работы с сэмплами:

    Код:
    def find_loop(item, search_samples, precision):
        item = Item(item, block_size=search_samples)
        samples = item.samples.get_all()
    
    
    class Item:
    
        def __init__(self, item, use_ts=True, block_size=1024):
            self.item = item
            self.take = RPR_GetActiveTake(self.item)
            self.playrate = RPR_GetMediaItemTakeInfo_Value(self.take, "D_PLAYRATE")
            self.PCM_source = RPR_GetMediaItemTake_Source(self.take)
            self.samplerate = RPR_GetMediaSourceSampleRate(self.PCM_source)
    
            self._start = RPR_GetMediaItemInfo_Value(self.item, "D_POSITION")
            self._len = RPR_GetMediaItemInfo_Value(self.item, "D_LENGTH")
            self._get_range(use_ts)
    
            self.samples = ItemSamples(self, block_size)
    
        def _get_range(self, use_ts):
            sel_start = sel_end = None
            if use_ts:
                loop_tr = RPR_GetSet_LoopTimeRange(0, 0, 0, 0, 0)
                sel_start, sel_end = loop_tr[2], loop_tr[3]
            if not sel_start or sel_end == sel_start:
                sel_start = self._start
                sel_end = self._start + self._len
    
            sel_start = max(sel_start, self._start)
            sel_end = min(sel_end, self._start + self._len)
            if sel_end - sel_start < 0:
                RPR_ShowMessageBox(
                    "Time selection out of item range!", "Note", 0)
    
            self.open()
    
            self.start = (sel_start - self._start) * self.playrate
            self.len = (sel_end - sel_start) * self.playrate
            self.end = self._start + self._len
            self.len_spls = int(self._len * self.samplerate)
    
            self.close()
    
        def open(self):
            if self.playrate != 1:
                RPR_SetMediaItemTakeInfo_Value(self.take, "D_PLAYRATE", 1)
                RPR_SetMediaItemInfo_Value(
                    self.item, "D_LENGTH", self._len * self.playrate)
    
        def close(self):
            if self.playrate != 1:
                RPR_SetMediaItemTakeInfo_Value(
                    self.take, "D_PLAYRATE", self.playrate)
                RPR_SetMediaItemInfo_Value(self.item, "D_LENGTH", self._len)
    
            RPR_UpdateTimeline()
    
    
    class ItemSamples:
    
        def __init__(self, item, block_size=1024):
            self.channels_amount = RPR_GetMediaSourceNumChannels(item.PCM_source)
            self.audio = RPR_CreateTakeAudioAccessor(item.take)
    
            self._block_size = block_size
            self._n_blocks = int(item.len_spls / block_size)
            self._extra_spls = item.len_spls - block_size * self._n_blocks
            self._buf_preset = list([0] * block_size * self.channels_amount)
            self.item = item
    
        def get_start_time(self, sample_offset):
            self.item.open()
            if sample_offset < 0:
                retval = self.item.end - (
                    (sample_offset * self.channels_amount) / self.item.samplerate)
                self.item.close()
                return retval
            retval = self.item.start + (
                (sample_offset * self.channels_amount) / self.item.samplerate)
            self.item.close()
            return retval
    
        def get_block(self, block=False, sample=False):
            if block is False and sample is False:
                raise Exception('block or sample offset has to be specified.\
                    block = %s, sample = %s' % (block, sample))
            if block is not False:
                block_size = self._block_size
                start = self.get_start_time(block * block_size)
                start_in_spls = block * block_size
                if block == self._n_blocks:
                    block_size = self._extra_spls
            if sample is not False:
                if block:
                    raise Exception(
                        'only block, or sample can be assigned at time')
                if self.item.end - sample < block_size:
                    block_size = self.item.end - sample
                start = self.get_start_time(sample)
                start_in_spls = sample
    
            self.item.open()
            samplebuffer = self._buf_preset
    
            RPR_GetAudioAccessorSamples(self.audio, self.item.samplerate,
                                        self.channels_amount, start,
                                        block_size, samplebuffer)
    
            samples = list()
            for sample in range(block_size):
                channels = list()
                for channel in range(self.channels_amount):
                    pos = sample * self.channels_amount + channel
                    channels.append(samplebuffer[pos])
                idx = start_in_spls + sample
                samples.append(Sample(idx, channels))
    
            RPR_DestroyAudioAccessor(self.audio)
            self.item.close()
            return samples
    
        def get_all(self):
            samples = list()
            for block in range(self._n_blocks):
                samples.append(self.get_block(block=block))
            return samples
    
    
    class Sample:
    
        def __init__(self, idx, channels):
            self.idx = idx
            self.channels_amount = len(channels)
            self.channels = tuple(channels)
    
    причем, простой копипаст с "переводом" на питон работает отлично. Что я тут могу не оттуда запускать?

    P.S. ацессор удалял при каждой итерации, а добавлял в конструкторе...
     
    Последнее редактирование: 25 май 2018 в 19:49
  38. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    так, все, кастую в тему @EUGEN27771 !

    я стопудово нахожу правильные индексы одинаковых сэмплов, во:
    2018-05-26_02-55-23.png

    если сдвинуть на ~10 сэмплов, получается вот:
    2018-05-26_02-57-34.png


    Я просто время как-то не так конвертирую (вырезка из кода):
    Код:
    def find_loop(item, search_samples, precision):
        item = Item(item, block_size=search_samples)
        pr('length in samples: %s' % item.len_spls)
        samples = item.samples
    
        start_buf = samples.get_block(block=0)
        end_buf = samples.get_block(sample=-search_samples)
    
        for sample in range(search_samples):
            start_spl = start_buf[sample]
            end_spl = end_buf[sample]
            loop = CheckLoop(start_spl, end_spl, precision)
            if loop.check is True:
                time1 = item.get_time_from_sample_idx(loop.idx[0])
                time2 = item.get_time_from_sample_idx(loop.idx[1])
                pr('values %s, %s' % (loop.start_spl_val, loop.end_spl_val))
                pr('time:')
                return time1, time2
    class Item:
    
        def __init__(self, item, use_ts=True, block_size=1024):
            self.item = item
            self.take = RPR_GetActiveTake(self.item)
            self.playrate = RPR_GetMediaItemTakeInfo_Value(self.take, "D_PLAYRATE")
            self.PCM_source = RPR_GetMediaItemTake_Source(self.take)
            self.samplerate = RPR_GetMediaSourceSampleRate(self.PCM_source)
    
            self._start = RPR_GetMediaItemInfo_Value(self.item, "D_POSITION")
            self._len = RPR_GetMediaItemInfo_Value(self.item, "D_LENGTH")
            self._get_range(use_ts)
    
            self.samples = ItemSamples(self, block_size)
    
    def get_time_from_sample_idx(self, idx):
            return self.start + idx / self.samplerate * self.playrate
    --- добавлено 25 май 2018 в 21:00 ---
    но вообще меня беспокоит, что на таком длинном фрагменте он начинает находить лупы только при растягивании окна поиска почти на весь отрезок...
    В прошлом варианте находил больше одинаковых сэмплов.

    P.S. не, время, вроде правильно находит. Значит заматчить не может с нужной точностью...
    Вообще, сэмплы эти орагнные, оказывается, очень противные. Ни zero-ceossing не работает, ни endlesswav...
    Надо какой-то убер-способ придумывать.
    Попробую ща поискать на чем-то еще
     
    Последнее редактирование: 25 май 2018 в 21:55
    Slick нравится это.
  39. Slick

    Slick IDDQD

    Регистрация:
    13 май 2008
    Сообщения:
    1.874
    Симпатии:
    794
    Род занятий:
    Аранжировщик, Саунд Дизайнер
    Адрес:
    Москва, Апрелевка
    @PianoIst, крутую штуку делаешь. постоянно приходится искать эти точки, чтоб без швов получалось...
     
  40. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    @Slick, да чет нихрена не выходит...
    увеличиваю точность попадания по стыкам (и это еще без учета формы волны), и перестает детектироваь вообще.
    А с точностью до +- километр и смысла нет...
     
  41. @Michael

    @Michael Well-Known Member

    Регистрация:
    14 дек 2010
    Сообщения:
    776
    Симпатии:
    1.179
    Пол:
    Мужской
    Адрес:
    Орёл / Москва
    Кинь RPP с кусками, склеенными руками.
     
    Последнее редактирование: 26 май 2018 в 12:15
    PianoIst нравится это.
  42. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    @@Michael, а я разобрался. Кой-чего не так обозвал, и индекс сэмпла неправильно вычислялся.
    Ща все норм :)
    Добавлю окошко для проверки сходимости, rms-окно для вычленения паттернов и покажу.
    Просто это предполагается как пакет (чтоб настройки хранить и экспортировать сразу для нескольких скриптов), поэтому и выложу позже, и написать все надо самому
     
    Aleksandr Oleynik нравится это.
  43. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    пока без rms-окна, но поскольку уже и так время поиска получается достаточно приличное, думаю, сделать выбор: по "точной подгонке", или по rms + кроссфейд перехода.
    Ну и это... тут только алгоритм поиска пока, автоматиацию нарезки позже сделаю.
    Ищет точки с начала и с конца, где все каналы на одинаковом значении,
    проверяет, достаточно ли коррелируют 100 сэмплов назад от этих точек (грубо говоря, похожая волна или нет), нет - ищет новую точку
     
    CerberPic нравится это.
  44. EUGEN27771

    EUGEN27771 Well-Known Member

    Регистрация:
    23 апр 2010
    Сообщения:
    2.231
    Симпатии:
    1.895
    Пол:
    Мужской
    @PianoIst,
    ---------------------
    Этот код изначально был на EEL, кто-то переложил на Lua.
    В EEL можно за раз получить не более 65536 семплов, поэтому время делилось на блоки по 65536. То есть, получается какое-то кол-во полных блоков по 65536.
    И один неполный блок - остаток.
    Если playrate = 1 - акцессор работает в разы быстрее, и в Lua, и в EEL. Поэтому в начале такая манипуляция с playrate, сброс, а в конце - восстановление.
    Семплы, конечно же, можно получить начиная с любой точки
    По поводу акцессора, без привязки к конкретной задаче.
    Если делать на Lua - можно учесть некоторые моменты - про Питон не скажу, наверное, в чем-то похоже.
    В Lua можно за один раз взять очень много семплов, хотя кол-во все равно ограничено - не помню точно, 2^21 - 1 или 2^22 - 1 .
    Если аудио длинное - тоже нужно делать частями. Однако блоки можно сделать большими.
    Есть еще несколько нюансов по производительности - это важно, когда нужно перебрать миллионы или десятки миллионов семплов.
    В Lua итерация сама по себе медленная, а итерация по reaper.array еще намного медленнее, чем по родной таблице.
    Из reaper.array нужно сделать таблицу(есть ф-я в API), и идти уже по таблице, это ускорит процесс.
    Локальные ф-и в Lua работают на 30-50% быстрее глобальных.
    Если некая ф-я вызывается пару миллионов раз - есть смысл сделать ее локальной - относится не только к этой теме, а вообще.
    То есть, тупо написав, например, в начале кода или прямо перед циклом на 100500 итераций:
    local abs = math.abs; local sin = math.sin; -- получаем + 30% - практически на шару ("Lua Performance Tips." - тут же есть и другие рекомендации).
    Можно подкрутить сборщик мусора, тоже немного помогает, что конкретно - не помню.
    Сделав все эти манипуляции можно получить прирост производительности в 2-3 раза, хотя eel в любом случае будет на порядок быстрее.
    К некоторым задачам можно подобрать альтернативные решения. В одном скрипте нужно было находить участки тишины, для каждого трека в проекте.
    То есть, для всех всех айтемов на каждом треке, все аудио, с учетом пересечений, перекрытий и тп, а потом еще и миди добавилось. Что-то типа глобального гейта.
    Единственное - особая точность по времени не требовалась, что и помогло. Через getpeaks этот номер прокатил, даже точность регулируется, проекты с кучей аудио анализируются практически незаметно(кто использовали ничего не сказали - значит, не заметили;)).
    --- добавлено 26 май 2018 в 19:22 ---
    Ага... Значит не зря я долго писал.
     
    Aleksandr Oleynik и PianoIst нравится это.
  45. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    @EUGEN27771, спасибо! очень полезное дело!
    В питоне, думаю, надо будет в перспективе все расчеты на numpy перевести (он все преобразует в immutable и хреначит на голом С).
    Чет никак не могу побороть свою лень и начать писать на lua... Просто в библиотеке питона уже боль-менее разобрался, а в lua опять ночами читать... Здесь лень списываю на достаточно специфическую задачу, ради которой юзер и может привязать к риперу интерпретатор ;)
     
  46. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    вроде, работает)
    Правда, в конце хотел похвастаться, что rms отлично находит щипки у домры, хоть и может не попать по форме волны. но что-то пошло не так... Видно, надо окошко для усреднения уменьшить, сейчас 250 сэмплов
    Надо забацать гибрид, с очень щадящим режимом по форме волны + настраиваемым rms

     
    Slick и Aleksandr Oleynik нравится это.
  47. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    чет не могу найти, как экшн запустить... Раньше же где-то откапывал..
    --- добавлено 27 май 2018 в 17:49 ---
    шит. OnCommand же. А насколько опасно использовать экшны SWS по id?
    --- добавлено 27 май 2018 в 17:51 ---
    и это нашел: RPR_NamedCommandLookup( command_name )
     
    Aleksandr Oleynik нравится это.
  48. PianoIst

    PianoIst Well-Known Member

    Регистрация:
    19 май 2010
    Сообщения:
    2.492
    Симпатии:
    2.107
    Пол:
    Мужской
    Род занятий:
    Аранжировка, солист-пинанист
    Адрес:
    Новосибирск
    А объясните, пожалуйста:
    Код:
    ( retval, proj, extname, key, valOutNeedBig, valOutNeedBig_sz ) = RPR_GetProjExtState(proj, extname, key, valOutNeedBig, valOutNeedBig_sz )
    что такое valOutNeedBig, valOutNeedBig_sz
    насколько я понимаю, первое - это собственно дата, которую сохраняли
    retval, это, видимо, успешность операции
    а valOutNeedBig_sz?
    Или я совсем неправильно думаю?
    --- добавлено 27 май 2018 в 18:39 ---
    чет не въезжаю я...
    Код:
    from reaper_python import *
    from misc import pr
    import pickle
    
    obj = {"one": 123, "two": [1, 2, 3]}
    output = pickle.dumps(obj, 2)
    pr(output)
    
    RPR_SetProjExtState(0, 'Levitanus_sample_editing_pack', 'test', output)
    
    valOutNeedBig = 0
    valOutNeedBig_sz = 0
    retval = RPR_GetProjExtState(0, 'Levitanus_sample_editing_pack', 'test',
                                 valOutNeedBig, valOutNeedBig_sz)
    pr(retval)
    pr(valOutNeedBig)
    pr(valOutNeedBig_sz)
    
    вывод:
    Код:
    b'\x80\x02}q\x00(X\x03\x00\x00\x00oneq\x01K{X\x03\x00\x00\x00twoq\x02]q\x03(K\x01K\x02K\x03eu.'
    (1, 0, 'Levitanus_sample_editing_pack', 'test', '0', 0)
    0
    0
    
    вопрос 1: можно ли так байты паковать?
    вопрос2: почему не могу распаковать?
     

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