Old 03-30-2016, 09:57 AM   #1
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default Help a Lua Toddler

Ok, I'm trying to get with lua from baby steps, so I can later understand it more from a fundamental level. Tell me, what's wrong with line 23 bolded below... trying to combine numeric var X with string Y to get a track name of "X# TrackName"...

Code:
  -- get the collection of selected tracks
  Selected_Tracks = reaper.CountSelectedTracks(0)
 
   -- Loop through selected tracks if > 0
  if  Selected_Tracks > 0 then
  x = 1
    for i = 0,  Selected_Tracks-1  do
      
      -- Get the next item i in the selected tracks collection
      track = reaper.GetSelectedTrack(0, i)
  
      -- Get the track name from selected item
      retval, track_name = reaper.GetSetMediaTrackInfo_String(track, "P_NAME", "", false)
      
      -- Prepend name with number x
      track_name = x .. "  " .. track_name
           
      -- Update with the modified track name 
        reaper.GetSetMediaTrackInfo_String(track, "P_NAME", track_name, true)
      
    end -- end loop iteration
  end -- end if / then parse
Also... is it necessary to pre-define things like below with vars...

Code:
track = reaper.GetSelectedTrack(0, i)
retval, track_name = reaper.GetSetMediaTrackInfo_String(track, "P_NAME", "", false)
... or can that be written like below (bolded bit) ...
Code:
retval, track_name = reaper.GetSetMediaTrackInfo_String(reaper.GetSelectedTrack(0, i), "P_NAME", "", false)

Last edited by Lawrence; 03-30-2016 at 10:04 AM.
Lawrence is offline   Reply With Quote
Old 03-30-2016, 10:14 AM   #2
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Ah... got it...

Code:
  -- The is for learning purposes only, to crate a script that
  -- allows sequentially numbering track names to get a feel for lua
  
  -- Most of the code was ripped from genius X-Raym
   
  -- get the collection of selected tracks
  Selected_Tracks = reaper.CountSelectedTracks(0)
 
  -- Loop through selected tracks if > 0
  if  Selected_Tracks > 0 then
  x = 1
    for i = 0,  Selected_Tracks-1  do
      
      -- Get the next item i in the selected tracks colletion
      track = reaper.GetSelectedTrack(0, i)
  
      -- Get the track name from selected item
      retval, track_name = reaper.GetSetMediaTrackInfo_String(track, "P_NAME", "", false)
      
      -- Prepend name with number x
           track_name = x .. ' ' .. track_name
           
      -- Update with the modified track name 
        reaper.GetSetMediaTrackInfo_String(track, "P_NAME", track_name, true)
     
      -- increment x
      x = x + 1
    end -- end loop iteration
  end -- end if / then parse
Lawrence is offline   Reply With Quote
Old 03-30-2016, 10:28 AM   #3
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Ok... I'm getting the hang of this so if there are any other LUA toddlers around maybe this will help.

What I did was (am doing) is to reduce a couple of the API calls to a "myfunctions.lua" file in the Reaper\lua folder so when I write my learning scripts I won't have to type those out and or remember how they work.

This way the scripts are not full of redundant API code. Example below...

Code:
  -- The is for learning purposes only, to crate a script that
  -- allows sequentially numbering track names to get a feel for lua
  
  -- Most of the code was ripped from X-Raym
  
  -- myfunctions.lua in Program Files\Reaper\lua
  -- this file reduces some of the API calls to simpler code
  require "myfunctions"
   
  -- get the collection of selected tracks
  Selected_Tracks = reaper.CountSelectedTracks(0)

  -- Loop through selected tracks if > 0
  if  Selected_Tracks > 0 then
  x = 1
    for i = 0,  Selected_Tracks-1  do
      
      -- Get the next item i in the selected tracks colletion
      track = reaper.GetSelectedTrack(0, i)
  
      -- Get the track name from selected item
       TrackName = GetTrackName(track)
      
      -- Prepend name with number x
          TrackName = x .. ' ' .. TrackName
           
      -- Update with the modified track name 
       SetTrackName(TrackName)
     
      -- increment x
      x = x + 1
    end -- end loop iteration
  end -- end if / then parse
So my intent here is (for me, mmv) to wrap most common API functions like that into the myfunctions.lua file to make some of this a good bit easier for me in general as I go along with this process of learning...


Code:
  -- myfunctions.lua
  -- get and return the track name
  function GetTrackName(track)
    retval, TrackName = reaper.GetSetMediaTrackInfo_String(track, "P_NAME", "", false)
    return TrackName
  end
  
  -- set the track name
  function SetTrackName(TrackName)
    reaper.GetSetMediaTrackInfo_String(track, "P_NAME", TrackName, true)
  end
Also, how do you guys debug in the Reaper IDE? How do you watch values? I can see individual vars show up in the pane on the right but I want to display an array and it's current values, and don't see how to add that to that pane.

Last edited by Lawrence; 03-30-2016 at 11:25 AM.
Lawrence is offline   Reply With Quote
Old 03-30-2016, 02:52 PM   #4
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

I don't use the Reaper IDE, so I can't help you there - I find Notepad++ with X-Raym's syntax highlighting and all that jazz far easier to use.

For debugging, I use this function from X-Raym's tutorials:
Code:
function Msg(message)
	reaper.ShowConsoleMsg(tostring(message).."\n")
end
For your array, you could write a new function like this, I think:
Code:
function MsgArray(arrayname)

        -- Google is telling me that this gets you the length, I've never tried it
        -- It may also misbehave if your array elements aren't consecutive, eg. i = 1, 2, 5, 12...
        for i = 1, table.getn(arrayname) do
                Msg("Array Element #"..i.." = "..arrayname[i])
        end
end
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna is offline   Reply With Quote
Old 03-30-2016, 03:24 PM   #5
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Lawrence View Post
I want to display an array
Really technically, Lua doesn't have arrays, it only has tables. But a table with contiguous integer keys starting from 1 (ie keys 1, 2, 3, 4...) works as a suitable substitute for arrays.

Remember to watch out that 0 isn't a valid key to use for this use case of the tables! (This was at first agonizing coming from other languages but I have learned to remember that with Lua.)
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 03-30-2016, 03:58 PM   #6
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Thanks.

So if I init a var like this... names = {}

Then run a loop through something like track names sequentially adding them to the array/table, with the upper loop bounds being = to the selected track count...

names[i] = trackname

I assume the names table/array var will then contain all of those items that were returned from all of the track names. I think my code is broken (no real surprise there, I'm kinda bumbling through early on) because doing that and then parsing names[1] for a value or doesn't return anything and/or throws an error.

I'm not at the code now but I may indeed have started my count at 0.

Last edited by Lawrence; 03-30-2016 at 04:06 PM.
Lawrence is offline   Reply With Quote
Old 03-30-2016, 04:18 PM   #7
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

Starting at zero works perfectly fine if you specifically add an item at index zero, i.e.
Code:
item_array = {}
for i = 0, num_items do
    item_array[i] = blahblahblah
end
However, you can fill an array when you initialize it, in which case the first value is placed at index 1. For instance, if you were doing something that requires the numbers of the Fibonacci sequence:
Code:
fib_nums = {1, 1, 2, 3, 5, 8, 13, 21}

blahblah = fib_nums[3] -- would return 2
blahblah = fib_nums[0] -- would be nil
Lawrence - care to paste your code? It's always possible that you're doing the array part correcting and whatever function is giving you the name is messing up.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna is offline   Reply With Quote
Old 03-30-2016, 05:56 PM   #8
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

I'll post it later when I get back to the laptop. Thanks.
Lawrence is offline   Reply With Quote
Old 03-30-2016, 06:49 PM   #9
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Lokasenna View Post
Starting at zero works perfectly fine if you specifically add an item at index zero
I could swear I've read integer zero should not be used as a table key if predictable array like behavior is to be expected. Maybe I remember wrong and it was about something else...
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 03-30-2016, 07:01 PM   #10
schwa
Administrator
 
schwa's Avatar
 
Join Date: Mar 2007
Location: NY
Posts: 15,812
Default

Quote:
Originally Posted by Xenakios View Post
I could swear I've read integer zero should not be used as a table key if predictable array like behavior is to be expected. Maybe I remember wrong and it was about something else...
Lokasenna's example is right. Lua tables are associative arrays, so arr[0]="hello" is exactly as valid as arr["foo"]="hello".

When you initialize a table from a list, like arr={"foo", "bar", "etc"}, then Lua populates the associative array for you, starting from index 1, so arr[1]=="foo" in this case.
schwa is offline   Reply With Quote
Old 03-30-2016, 07:55 PM   #11
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by schwa View Post
Lokasenna's example is right. Lua tables are associative arrays, so arr[0]="hello" is exactly as valid as arr["foo"]="hello".
http://www.lua.org/pil/11.1.html

Says :

Quote:
...it is customary in Lua to start arrays with index 1. The Lua libraries adhere to this convention; so, if your arrays also start with 1, you will be able to use their functions directly.
But they don't really expand in that page why the Lua libraries prefer starting at index 1...I vaguely recall that was explained somewhere else.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 03-30-2016, 08:07 PM   #12
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default

I was wondering that earlier. This is the best explanation I could find:
Quote:
Lua is descended from Sol, a language designed for petroleum engineers with no formal training in computer programming. People not trained in computing think it is damned weird to start counting at zero. By adopting 1-based array and string indexing, the Lua designers avoided confounding the expectations of their first clients and sponsors.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate
Lokasenna is offline   Reply With Quote
Old 03-31-2016, 07:12 AM   #13
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

I appreciate your help L. What I'm doing is writing various functions and testing them and when they work I'll move them over to the 'myfunctions' file. Here's the function that I'm likely screwing up somehow, looking for it to return an array of track names.

The loop count actually did start at 1, probably because I paid attention to that text bit that X-Man referenced when I was reading up on arrays.

Code:
-- get the names of all selected tracks
 function GetSelectedTrackNames()
  Selected_Tracks = reaper.CountSelectedTracks(0)
  
  Sel_Track_Names = {}    -- new array
      for i=1, Selected_Tracks do
        Sel_Track_Names[i] = 0
      end
  return Sel_Track_Names
 end
So basically, my functions file will be loaded up with all kinds of functions like that. Looking at that code, should that return var be loaded with those values or am I doing it wrong? I suspect the code in the loop is wrong, but looking at the examples I followed the = 0 didn't make much sense.

Should it be Sel_Track_Names[i] = (API gettrackname(index)) ?

Keep in mind that, for the most part, I have no clue what I'm doing yet. Here's the functions file. Does this look more correct? Sel_Track_Names[i] = GetTrackName(i)

Code:
  -- get and return the track name
  function GetTrackName(track)
    retval, TrackName = reaper.GetSetMediaTrackInfo_String(track, "P_NAME", "", false)
    return TrackName
  end
  
  -- set the track name
  function SetTrackName(TrackName)
    reaper.GetSetMediaTrackInfo_String(track, "P_NAME", TrackName, true)
  end

-- get the names of all selected tracks
 function GetSelectedTrackNames()
  Selected_Tracks = reaper.CountSelectedTracks(0)
  
  Sel_Track_Names = {}    -- new array
      for i=1, Selected_Tracks do
        Sel_Track_Names[i] = GetTrackName(i)
      end
  return Sel_Track_Names
 end
So I try to get those values from another script file like below with no luck...

Quote:
require "myfunctions"
tracks = GetSelectedTrackNames -- return the track name array?

reaper.ShowConsoleMsg(tostring(tracks[1]).."\n")

Last edited by Lawrence; 03-31-2016 at 07:27 AM.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 07:41 AM   #14
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

Btw the bit of code to get the number of elements in a table (table.getn) that Lokasenna posted is for a previous version of Lua. Now we prefix the table with '#' to get the number of entries...
Code:
t = {} -- init table, #t will be zero
t = {"bling", "blop", "blap"}
-- now #t = 3

for i=1,#t,1 do
  reaper.ShowConsoleMsg(t[i].."\n")
end
So you can fill your table after init'ing with t={} using...
Code:
t[#t+1]="blam"
... which always adds an entry on to the table at the end.

The thing that's wrong with the code is that you are passing a number to reaper.GetSetMediaTrackInfo_String when it wants a MediaTrack object. To get the object you can use...
Code:
local track=reaper.GetSelectedTrack(0,i)
Sel_Track_Names[i] = GetTrackName(track)
... where the zero is for current project. It's actually something to look out for anyway, because some API functions return or use track index numbers and some return or use MediaTrack objects.
snooks is offline   Reply With Quote
Old 03-31-2016, 07:57 AM   #15
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Actually, I may not even need a table or array for this adventure. This seems to work and returns those things in a way where I can just make a delimited string or something out of them to make the collection what I want...

Code:
 require "myfunctions"

     Sel = GetSelTracks()
  
      for i=0,  Sel-1 do
        CurName = GetTrackName(GetCurTrack(i))  
        reaper.ShowConsoleMsg(tostring(CurName).."\n")
      end
I think my earlier code was failing because I wasn't adding () to some of my function calls.

Additional question... is there a way in the Reaper IDE to comment out a selected block of code with a key command or do you have to manually do it line by line? I'm kinda learning LUA and Ruby at the same time and Ruby kinda pisses me off with it's comment char being a modified character (#), which seems bizarre to me, why they'd pick a key modified character for a line comment.

Last edited by Lawrence; 03-31-2016 at 08:19 AM.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 08:39 AM   #16
DarkStar
Human being with feelings
 
DarkStar's Avatar
 
Join Date: May 2006
Location: Surrey, UK
Posts: 19,679
Default

Code:
 require "myfunctions"

     Sel = GetSelTracks()

--[[
All this is commented out:

Additional question... is there a way in the Reaper IDE to comment out
a selected block of code with a key command or do you have to manually
do it line by line?   I'm kinda learning LUA and Ruby at the same time and
Ruby kinda pisses me off with its comment char being a modified character
(#), which seems bizarre to me, why they'd pick a key modified character
for a line comment.
]]
  
      for i=0,  Sel-1 do
        CurName = GetTrackName(GetCurTrack(i))  
        reaper.ShowConsoleMsg(tostring(CurName).."\n")
      end

PS, if you are using functions, try right-clicking in the main Lua window
__________________
DarkStar ... interesting, if true. . . . Inspired by ...

Last edited by DarkStar; 03-31-2016 at 10:20 AM.
DarkStar is offline   Reply With Quote
Old 03-31-2016, 08:40 AM   #17
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Ok... moving forward with my baby learning scripts, how do you strip numeric characters? My googling so far has been inconclusive.

Example in .NET:
str = "abc123def"
str = Regex.Replace(str, @"\d", "")
returns "abcdef"

Not sure how (or the best way) to do this in LUA.

Never mind, I found it. gsub('%d','') Nice.

Last edited by Lawrence; 03-31-2016 at 08:55 AM.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 08:43 AM   #18
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Quote:
Originally Posted by DarkStar View Post
All this is commented out:
Yeah, I was wondering if there is a key combo, like selecting a block of text and hitting CTL+SomeKey or whatever to comment out the selection or do you always have to do it manually?

And again, much appreciate you guys who are way ahead of me taking the time to help.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 09:13 AM   #19
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

Speaking of comments, very good trick with multi-line comments...
Code:
--[[
this is commented
--]]

---[[
this isn't commented
--]]
So you can comment/uncomment blocks by adding/removing a single character.
snooks is offline   Reply With Quote
Old 03-31-2016, 09:32 AM   #20
schwa
Administrator
 
schwa's Avatar
 
Join Date: Mar 2007
Location: NY
Posts: 15,812
Default

Quote:
Originally Posted by Xenakios View Post
But they don't really expand in that page why the Lua libraries prefer starting at index 1...I vaguely recall that was explained somewhere else.
I assume they mean that the standard table library functions will behave as expected only if arrays are indexed from 1.

However, things seem to work as expected even with zero-based arrays:

Code:
arr={"A","B","C"}
table.insert(arr, 1, "X")
print(arr[1] .. arr[2] .. arr[3] .. arr[4])

arr={}
arr[0]="A"
arr[1]="B"
arr[2]="C"
table.insert(arr, 1, "X")
print(arr[0] .. arr[1] .. arr[2] .. arr[3])

Output:

XABC
AXBC

http://www.lua.org/cgi-bin/demo is handy btw.
schwa is offline   Reply With Quote
Old 03-31-2016, 10:05 AM   #21
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Baby's first script using the supporting "myfunctions.lua" file. Nothing that nobody has done before but educational for me for learning. The question now is how to replace the input fields with buttons...






Code:
 -- myfunctions.lua is a lua file in Reaper\lua serving as an 
 -- include to reduce some of the API functions to shorter code
   require "myfunctions"
 
     -- configure an input box for the choices to either
     -- strip all numbers from track and/or also append numbers 
  defaultvals_csv = "0,0,0"
  retval, retvals_csv = reaper.GetUserInputs("Modify Track Names", 2, "Strip Numbers 1=Yes 0=No,Prefix Numbers 1=Yes 0=No", defaultvals_csv)  
  strip,prefix = retvals_csv:match("([^,]+),([^,]+)")
 
     -- if either choice is true then proceed
     if strip == "1" or append == "1" then
     
     Sel = GetSelTracks()  -- get the selected track collection
                    
           -- iterate through selected tracks
           for i=0,  Sel-1 do
              
                  Track = GetCurTrack(i)  -- get the current track
                  CurName = GetTrackName(Track)   -- get current name
                  
                  if strip=="1" then   -- if strip is true
                      CurName =  CurName:gsub('%d','') -- strip all numbers from name            
                      SetTrackName(Track,CurName)  -- replace with new name
                  end 
              
                  if prefix == "1" then  -- if prepend is true
                  
                  end                    
            end -- end tracks iteration
      end -- end proceeding
Man, LUA is really great. I sit here pondering the possibilities of what might be if LUA in Reaper could use XML skins for GUI's, where you could easily add buttons and option boxes and all kinds of things like that in an XML skin and have LUA triggering it all in the background... like web pages... or like how S1 does with Javascript and XML.

Last edited by Lawrence; 03-31-2016 at 10:33 AM.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 10:29 AM   #22
DarkStar
Human being with feelings
 
DarkStar's Avatar
 
Join Date: May 2006
Location: Surrey, UK
Posts: 19,679
Default

^^^^
(Your pics are not showing here )
How about a LuaXML_graphics parser?

Jumping into the school-room:
Quote:
Originally Posted by Lawrence View Post
Code:
 -- myfunctions.lua is a lua file in Reaper\lua serving as an 
 -- include to reduce some of the API functions to shorter code
   require "myfunctions"
 
     -- configure an input box for the choices to either
     -- strip all numbers from track and/or also append numbers 
  defaultvals_csv = "0,0,0"
  -- etc
I would like to put some Lua 'library' files, with commonly-used functions, in a sub-folder. e.g.
C:\Users\DarkStar\AppData\Roaming\REAPER\Scripts\D arkStar\LuaLibs

What do I need in the main Lua script?
__________________
DarkStar ... interesting, if true. . . . Inspired by ...
DarkStar is offline   Reply With Quote
Old 03-31-2016, 10:30 AM   #23
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Here's what I mean... just an XML form for script GUI's and the functions in LUA would be attached to the graphic objects by name like Javascript does... and designing GUI forms would be a breeze...

Code:
<Form name="DarkStar_Panel" title="Darkstar" windowstyle="floating above" attach="all fitsize">
<Vertical attach="all" spacing="0">
<Horizontal margin="0" attach="all">
   <ListView name="fileList" width="300" height="300" options="header selection" scrolloptions="border autohideboth" attach="all" persistence.id="MacroOrganizer.fileList"/>
<Vertical margin="0" options="unifysizes">
<Space/>
        <Button name="new" title="New" attach="left right"/>
        <Button name="edit" title="Edit." attach="left right"/>
        <Button name="delete" title="Delete" attach="left right"/>
        <Space/>
        <Button name="refresh" title="Refresh" attach="left right"/>
<Space/>
</Vertical>
</Form>
So in Javascript, the forms are prototypes that define and connect to the XML objects via parameter lists. You'd think you could do much the same with LUA like what probably happens on web pages using LUA...

Code:
this.initialize = function (context)
	{	
		componentclass.prototype.initialize.call (this, context);
		
		// create command selector
		this.commandSelector = ccl_new ("CCL:CommandSelector");
		this.commandSelector.name = "commandSelector";
		this.commandSelector.argColumnEnabled = true;
		this.commandSelector.addExcludedCategory (JSTRANSLATE ("DarkStar")); 
		this.children.push (this.commandSelector);
		
		// create parameters
		this.paramList.addParam ("add");
		this.paramList.addParam ("remove");
		this.paramList.addParam ("moveUp");
		this.paramList.addParam ("moveDown");
		this.paramList.addParam ("edit");
						
		this.paramList.addString ("title");
		this.paramList.addString ("group");
		this.paramList.addString ("description");
The extension GUI's like that are so much easier in Studio One, but the user scripting is kinda... non-existent.

Last edited by Lawrence; 03-31-2016 at 10:42 AM.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 10:32 AM   #24
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Quote:
Originally Posted by DarkStar View Post
What do I need in the main Lua script?
When I looked that up it gives the paths that LUA searches through for "requires" and that one, Program Files\Reaper\lua, was one I had to create to make my "myfunctions.lua" file visible to the scripts. I assume one of the default search paths for "requires" is \root, which in this case is the Reaper application directory (+ \lua) I guess.

No idea if you can manually define those search paths or use a literal file path in your requires statement but my guess is that a literal path might work.

requires 'C:\DarkStar\Functions\functions.lua'

... or something maybe. No idea. My reason for doing that 'myfunctions' file is to make the API a bit less visible in the code, to ease my understanding of LUA the language while learning and not so much looking at some of those long-ish API calls... and to make the manual coding a tiny bit smaller for those kinds of common things, like getting track names.

I mean, to me anyway, that's way cleaner than typing it out in full every time you use those API functions...

Code:
          for i=0,  Sel-1 do
              
                  Track = GetCurTrack(i)  -- get the current track
                  CurName = GetTrackName(Track)   -- get current name
                  
                  if strip=="1" then   -- if strip is true
                      CurName =  CurName:gsub('%d','') -- strip all numbers from name            
                      SetTrackName(Track,CurName)  -- replace with new name
                  end 
              
                  if prefix == "1" then  -- if prepend is true
                  
                  end                    
          end -- end tracks iteration
... so as I learn and test various more commonly used API functions I'll be adding them to that file in a similar way.

Also, for me, reducing it that way makes if look and feel a lot more like what I'm more used to, VB. It's already kinda similarly structured with the For/Ends and If/Ends and all that.

Last edited by Lawrence; 03-31-2016 at 10:56 AM.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 10:45 AM   #25
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

Quote:
Originally Posted by DarkStar View Post
I would like to put some Lua 'library' files, with commonly-used functions, in a sub-folder. e.g.
C:\Users\DarkStar\AppData\Roaming\REAPER\Scripts\D arkStar\LuaLibs

What do I need in the main Lua script?
If you have mylibrary.lua in that directory and really want to use require then you need to add a search term to the Lua Path variable...
Code:
package.path=reaper.GetResourcePath().."/Scripts/DarkStar/LuaLibs/?.lua;"..package.path
... then...
Code:
require("mylibrary")
I think what messed me up the last time was adding "blah/?" where require("blop.lua") wouldn't work when it looks like it should. But "?.lua" and require("blop") works. Require is a bit weird because it doesn't work with full paths/filenames and it really should imo.
snooks is offline   Reply With Quote
Old 03-31-2016, 11:05 AM   #26
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Actually, along those same lines, I'll probably wrap a lot of the RegEx functions into functions in that file, to not have to remember them all and just call them by some logical function name like with...

gsub('%d','')

... it would instead just be a function like...

function StripNumbers(var)
var = var:gsub('%d','')
Return var
end

So, for me the lazy with not a great memory, this....

CurName = CurName:gsub('%d','')

... would always be ...

CurName = StripNumbers(CurName)

... which would also reduce the need for some code commenting with the functions having logical names.

And looking at a lot of LUA source code, my use of camel case seems to be not all that typical, but it makes it more readable for me, habit I guess.

Last edited by Lawrence; 03-31-2016 at 12:53 PM.
Lawrence is offline   Reply With Quote
Old 03-31-2016, 01:46 PM   #27
DarkStar
Human being with feelings
 
DarkStar's Avatar
 
Join Date: May 2006
Location: Surrey, UK
Posts: 19,679
Default

Thank you Snooks; that worked (after a bit of tweaking for Windows ):

Code:
package.path=reaper.GetResourcePath().."\\Scripts\\DarkStar\\libraries\\?.lua;"..package.path
require("DS01")
to load the DS01.lua file
__________________
DarkStar ... interesting, if true. . . . Inspired by ...
DarkStar is offline   Reply With Quote
Old 03-31-2016, 02:23 PM   #28
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

Cool, it works with forward slashes on Windows too btw. If you want OSX users to use your scripts you should use forward slashes, if not then it doesn't matter.
snooks is offline   Reply With Quote
Old 03-31-2016, 09:23 PM   #29
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,770
Default

Can the forward slashes be denoted just as forward slashes or would they need to be pre-fixed with something similar to the backward sloshes being written as double backward slashes in DarkStar's example ?

-Michael
mschnell is offline   Reply With Quote
Old 04-01-2016, 05:48 AM   #30
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

No, you just write them the way I wrote them, only the backslashes need to be escaped because the backslash is an escape character itself, used for "\n" etc.

So because "\n" means new line, "C:\new folder\new file.lua" would be interpreted as..
Code:
C:
ew folder
ew file.lua
... if we didn't escape the backslashes "\\".

On the other hand, "C:/new folder/new file.lua" doesn't contain any escape characters and so nothing happens to it.

Last edited by snooks; 04-01-2016 at 05:56 AM.
snooks is offline   Reply With Quote
Old 04-01-2016, 07:00 AM   #31
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Hey Morpheus,

While your're here tutoring (and again, it's very kind of you to help so willingly so big props, much respect) ... can you give me a short use case example of when or where you might create (if you do) your own classes for any of your scripts?

As I look over the docs and other scripts and think about the kinds of things I might want to do as I move forward, redundancy is something I plan to avoid as much as possible so I wonder if I should be looking at doing some of that. For example with my baby script thing, how would it work to write an track class that wraps all of the lower level track API's into it with properties, or would that be mostly redundant?

For example: Would it make any sense to have a custom Track class that has properties like .name, .number, .color, .events (collection), .state (mute, solo, etc), etc, etc, and put that in a "requires" file to use with any script?

Thanks.

Last edited by Lawrence; 04-01-2016 at 07:05 AM.
Lawrence is offline   Reply With Quote
Old 04-01-2016, 10:35 AM   #32
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

No worries, I like bleating on about geeky stuff anyway. And arguing about it, but you know that.

A small technicality you're probably aware of but which is worth pointing out for future red pill swallowers is that Lua doesn't have classes built-in, but you can do OOPy stuff with tables, which have special attributes that can be used. There are a few pre-rolled solutions out there. I use this one...

https://github.com/Lazzle/ReaMIDI/bl...ires/class.lua

I've only really used that implementation in my slowly developing GUI library...

https://github.com/Lazzle/ReaMIDI/bl...s/el%20gui.lua

... which makes lots of use of inheritance.

But you can just use simple tables for most purposes...
Code:
function makeBeing(height,weight,shoe_size)
  local b={}
  b.height=height
  b.weight=weight
  b.shoe_size=shoe_size
  return b
end

zorg=makeBeing(190,70,12)
zarg=makeBeing(38472,83942,98)

print(zorg.height)
print(zarg.weight)
... and get them tucked away in their own namespace (another table)...

Code:
AlienFactory={}
function AlienFactory.makeBeing(height,weight,shoe_size)
  local b={}
  b.height=height
  b.weight=weight
  b.shoe_size=shoe_size
  return b
end

zorg=AlienFactory.makeBeing(190,70,12)
zarg=AlienFactory.makeBeing(38472,83942,98)

print(zorg.height)
print(zarg.weight)
... which can also be written as...

Code:
AlienFactory={
  makeBeing=function(height,weight,shoe_size)
    local b={}
    b.height=height
    b.weight=weight
    b.shoe_size=shoe_size
    return b
  end
}

zorg=AlienFactory.makeBeing(190,70,12)
zarg=AlienFactory.makeBeing(38472,83942,98)
So it's up to you whether you use the stuff the hardcore Lua gnomes have created for classes or not. I'd say unless you want to use inheritance then just use tables like ^.
snooks is offline   Reply With Quote
Old 04-01-2016, 10:45 AM   #33
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Nice. Thanks man.
Lawrence is offline   Reply With Quote
Old 04-01-2016, 12:57 PM   #34
snooks
Banned
 
Join Date: Sep 2015
Posts: 1,650
Default

You're welcome, it's a cool language. Have fun!
snooks is offline   Reply With Quote
Old 04-01-2016, 05:01 PM   #35
airon
Human being with feelings
 
airon's Avatar
 
Join Date: Aug 2006
Location: Berlin
Posts: 11,818
Default

Spk77 did a bunch of nice GUI elements. Perhaps it's useful to you as well.

It certainly helped me a bunch. If it's useful and you can improve it, send a little code back in .

http://forum.cockos.com/showthread.php?t=171432 Posts #53 and #55 in particular. MPL and Heda have written a ton of stuff too.
__________________
Using Latch Preview (Video) - Faderport 16 setup for CSI 1.1 , CSI 3.10
Website
"My ego comes pre-shrunk" - Randy Thom
airon is offline   Reply With Quote
Old 04-02-2016, 07:18 AM   #36
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Quote:
Originally Posted by snooks View Post
You're welcome, it's a cool language. Have fun!
It really is. I love the way it's free flowing and the general structure and syntax is something I really like.

Quote:
Originally Posted by airon View Post
Spk77 did a bunch of nice GUI elements. Perhaps it's useful to you as well.
I doubt if I'll get much into the GUI stuff as it is. I've actually asked Justin if there's a possibility of doing it all an arguably better way, with XML skins. In my view, having to manually create graphics like I see people doing is not a good approach at all... is arguably way more complex than it needs to be.

My AskJF question below about that hasn't been answered yet so maybe he's looking into it...

Quote:
On a scale of 1-10, where would you place the viability of LUA in Reaper using XML skins for GUI's? To design an XML skin with it's easy objects, buttons, textboxes, menus, etc, etc, and having it attached to LUA functions and code.
It seems a little nuts to me, for simple things like scripts, to have to manually code graphics, when most of these languages are being used on the web with normal control and graphic objects. I look at something like this code below...

Code:
    function digitButton (digit)
      return Button{ label = digit,
                     action = function ()
                               end
                   }
    end
... and wonder why that action function trigger above couldn't be a trigger from a simple XML skin button.

Last edited by Lawrence; 04-02-2016 at 07:27 AM.
Lawrence is offline   Reply With Quote
Old 04-02-2016, 07:39 AM   #37
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Lawrence View Post
It seems a little nuts to me, for simple things like scripts, to have to manually code graphics, when most of these languages are being used on the web with normal control and graphic objects.
Such things are not a property of the programming language but rather of the libraries available.

The Cockos developers have decided not to implement convenient to use GUI library facilities for ReaScript. That's just how it is. You may be able to roll your own...
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 04-02-2016, 08:03 AM   #38
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Quote:
Originally Posted by Xenakios View Post
Such things are not a property of the programming language but rather of the libraries available.

The Cockos developers have decided not to implement convenient to use GUI library facilities for ReaScript. That's just how it is. You may be able to roll your own...
I suppose (granted, with my limited understanding of embedded LUA or similar) my question would be... how difficult is that? In my mind it's not so much adding a graphic library as it is maybe just taking advantage of what kinda already exists on every system.

I mean, XML skins work on every system, they're all over the web and in use in all kinds of various tools, mp3 players, all kinds of things, so the coding to use them for interfaces would be (in my mind anyway) more just a matter of functions to use / connect to them... but again... my understanding of it all may be limited. In my mind, a Reaper script GUI would be nothing more than a local web page of sorts, with XML skins.

If you look at how Studio One does it with their extension system, they use a generic window class and invoking that generic (embedded or pre-setup I suppose, in the lower level classes) window class uses XML skins as a GUI. I can't personally imagine that Javascript can so easily do that, connect it's code functions directly to XML graphic objects, and LUA somehow can't.

In Reaper the same would be invoking a new instance of a Reaper window class, telling it that it's skin is "MySkin.xml", and connecting the XML graphic objects on that skin to LUA functions, with parameters.

In my (perhaps incorrect) thinking, LUA doesn't actually have to do anything graphically itself in that case, it only has to respond to the actions from an XML skin ... to click a button on an XML skin and have it fire a LUA function.

But again, maybe LUA simply isn't built that way, to make that so easy. No idea.

Last edited by Lawrence; 04-02-2016 at 08:25 AM.
Lawrence is offline   Reply With Quote
Old 04-02-2016, 09:19 AM   #39
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

Quote:
Originally Posted by Lawrence View Post
I mean, XML skins work on every system, they're all over the web
XML really has nothing to do with it. XML or not, Cockos would need to undertake a pretty heavy development effort to support any kind of "complicated" widget based GUIs for ReaScript. Making that work based on XML files would be a tiny portion of the work required.

How exactly do you imagine this would be easy and light weight to implement? Also cross platform...You seem to be forgetting Cockos does their GUIs with the low level win32 API. For example Studio One might have something that is far easier to use and implement for scripting based stuff.
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.

Last edited by Xenakios; 04-02-2016 at 09:24 AM.
Xenakios is offline   Reply With Quote
Old 04-02-2016, 09:30 AM   #40
Lawrence
Human being with feelings
 
Join Date: Mar 2007
Posts: 21,551
Default

Quote:
Originally Posted by Xenakios View Post
XML really has nothing to do with it. XML or not, Cockos would need to undertake a pretty heavy development effort to support any kind of "complicated" widget based GUIs for ReaScript. Making that work based on XML files would be a tiny portion of the work required.
Ok, thanks X. Perhaps I'm looking at it all wrong. I really thought it might be a relatively simple matter to create an XML button on a skin like below...

Quote:
<Button name="Do_Foo" title="Do Foo"/>
... and also define that button object in the LUA code to act on it. Of course, you'd have to code LUA to listen to that button, to define a parameter or object in LUA that represents that button object on the skin, to see the objects on the skin as addressable objects, but I thought that's what web pages and similar commonly do.

I suppose it's more complex than I imagined. I'll defer to your judgement on that obviously, being a real coder.

Thanks.
Lawrence is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 11:50 PM.


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