Jump to content


Photo

Save table to a TXT file, load table from this TXT file.

save table txt load table txt

  • Please log in to reply
8 replies to this topic

#1 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1599 posts
  • Gender:Male
  • Location:Spain

Posted 01 July 2018 - 10:22

I'm investigating how to get this: export a tabl inside a new TXT file, to have it saved for later sessions (one table for each TXT file, renamed differently).
 
In this way, days later it is possible to access this TXT to return the saved table and use it again in the tool, as if it were a bank.
 
Does anyone have a way of doing all this with a simple code? No extra-long functions to convert a table into a chain or things like that. The tables would not be much. They would contain at most 128 values.
 
I'm experimenting with the following code:
--
-- test area
--


function kng_write_txt( file, tbl )
    print( "------------------------ " )
    print( "write in "..file )
    io.output( io.open( file, "w" ) )
    io.write( tbl )
    io.close()
    print( "---- write done ----" )
end

function kng_read_txt(file)
    print( "------------------------ " )
    print( "read from "..file )
    io.input( io.open( file, "r" ) )
    local li
    for i in io.lines() do print(i) end
    -- no close needed: done by io.lines()
    print("---- read done ----")
end



function kng_test()
  local dir = os.currentdir() --dir for tool
  local txt = "txt/table_1.txt"
  local file = dir..txt

  local tbl =" { 1,2,3,4,5,6,7,8,9,10 } " --?????????????
  --local t = table.ToString(tbl)  ?????????????
  --print(t)
  kng_write_txt( file, tbl )
  --kng_read_txt( file )
end



KNG_TEST = vb:button {
  text = "Test",
  notifier = function() kng_test() end
}

At the moment, I have problems converting a table into a string. Possibly, it is convenient not to include the keys "{"  "}" , only the values. Is there nothing in LUA that allows this? Is it necessary to create a function that iterates between all the values to create the string? Subsequently, this string must be used to import the values again into the tool to create another table and load it.

 

Any simple suggestion?

 


Edited by Raul (ulneiz), 10 July 2018 - 23:03.

:excl: Development of my tools: Piano Roll EditorKangarooX120SamRenderPhraseTouch

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#2 Guest_ffx_*

Guest_ffx_*

    Composes without Wires burns Directly from Brain to DVD that is already in Store Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 3521 posts
  • Gender:Not Telling

Posted 01 July 2018 - 11:15

Read about JSON.

#3 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1862 posts
  • Gender:Not Telling

Posted 01 July 2018 - 11:15

The very quick and easy way is to use the Document class. It can be implemented in various ways, but here is a really simple way that's working:

I find that the Document XML import/export works really well, and don't really get the old talk about using other means of serialization/deserialization.

-- Create and define a Document the quick and simple way - from a "model" table.
-- Note that the Document lists are picky about differentiating between numberlists and string lists.
my_document = renoise.Document.create("MyDataID") {
  number_list = { 1, 2, 3 },
  string_list = { "1", "some_string", "3" },
}

-- Loads data from test.xml, if the file exists
my_document:load_from("test.xml")

oprint(my_document:property("string_list")[2].value)

my_document:property("string_list")[2].value = "Wow .. new data"

-- Save any changed data to test.xml
my_document:save_as("test.xml")


#4 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1599 posts
  • Gender:Male
  • Location:Spain

Posted 04 July 2018 - 12:47

The very quick and easy way is to use the Document class. It can be implemented in various ways, but here is a really simple way that's working:

I find that the Document XML import/export works really well, and don't really get the old talk about using other means of serialization/deserialization.
 

-- Create and define a Document the quick and simple way - from a "model" table.
-- Note that the Document lists are picky about differentiating between numberlists and string lists.
my_document = renoise.Document.create("MyDataID") {
  number_list = { 1, 2, 3 },
  string_list = { "1", "some_string", "3" },
}

-- Loads data from test.xml, if the file exists
my_document:load_from("test.xml")

oprint(my_document:property("string_list")[2].value)

my_document:property("string_list")[2].value = "Wow .. new data"

-- Save any changed data to test.xml
my_document:save_as("test.xml")

 

Then I will insist on using the XML format. I have already managed to successfully implement it to save XML banks in separate files. It will even allow you to check the mother folder to avoid errors.

 

os.mkdir(path) and io.exists(filename) work correctly in all operating systems? The documentation does not say anything about compatibility, but I understand that it should work on any operating system compatible with Renonise. If so, it is very easy to create and verify a directory to be able to save several XML files.

 

I attach the code that I created for the creation of XML data banks. If someone sees any improvement, you just have to mention it. From what I've tried, it works perfectly.

Spoiler

:excl: Development of my tools: Piano Roll EditorKangarooX120SamRenderPhraseTouch

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#5 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1862 posts
  • Gender:Not Telling

Posted 04 July 2018 - 13:08

I won't study the script in detail, but like i said before:

DON'T create a lot of viewbuilder objects in a scope that Renoise is running when the tool loads. As soon as the file is loaded, these objects will get created which consumes both time and memory for no reason. This will then even bloat the actual startup of Renoise.

It's very simple to wrap these ViewBuilder object creations inside functions that are called on a need-to-use basis.

#6 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1599 posts
  • Gender:Male
  • Location:Spain

Posted 04 July 2018 - 22:18

...

It's very simple to wrap these ViewBuilder object creations inside functions that are called on a need-to-use basis.

 

I'm trying to get used to this approach. Although the tools are not heavy and the performance is hardly affected, I want to make my tools as good as possible. The problem that I have, is that I use several LUA files and also several global ones, and some of them are ViewBuilder objects (surprisingly most are buttons with different shapes and uses).

 

Then, I would have to study how to put all these objects inside the functions to wrap them. I guess you mean that. For example, I use this:

XXX = vb:button {
}

--and then

YYY = vb:row {
  XXX,
  vb:button {
  },
  vb:button {
  }
}

And probably, one of those global ones is inside another LUA file. The tool I'm building has a 120-button pad and another 120 buttons that make up a virtual piano, basically, among a few other controls. Both button panels are defined by classes. Actually, I do not notice any performance problems, or initial load. Everything is going very fast. How important is the impact on the performance of loading the Viewbuilder objects?


:excl: Development of my tools: Piano Roll EditorKangarooX120SamRenderPhraseTouch

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#7 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1862 posts
  • Gender:Not Telling

Posted 05 July 2018 - 07:48

I know that some tools can add noticable startup time, but I don't know if it's due to bytecode compiling or bad code. I have encountered memory leaks due to non-collected viewbuilder objects though. You can get a tools memory usage by using collectgarbage (google).



#8 Raul (ulneiz)

Raul (ulneiz)

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1599 posts
  • Gender:Male
  • Location:Spain

Posted 06 July 2018 - 14:02

I know that some tools can add noticable startup time, but I don't know if it's due to bytecode compiling or bad code. I have encountered memory leaks due to non-collected viewbuilder objects though. You can get a tools memory usage by using collectgarbage (google).

 

I have been manipulating the code of my last tool checking the use of memory with collectgarbabe. I have come to the following conclusion:

 

I can build the tool in 2 ways (I've already checked):

 

1- The first loads all ViewVuilder functions and objects in memory, since the Renoise boot, and stays there all the time. In this way, it is possible to easily use the IDs of each object to manipulate it. In this way, it is possible to close the tool and reopen it and do not lose "the state" of the object. This approach makes my tool return about 2800KB with collectgarbage. But, it has two advantages. The first is once loaded in memory, always going very fast. The second is that it does not lose the state of each object. Here I use globals and locals to define the objects (without wrapping them in a function).

 

2- The second way is by wrapping each object definition within a function, which ends with the return of the object. Collectgarbaje returns about 750KB, a saving of about 2MB. However, the typical error of ID already registered appears, and before loading each object I have to force to equal each identifier = nil. This solves the problem, but it has a drawback. The tool loses the status of the object when it is closed. Since the tool has a multitude of controls, it is not desirable to lose the configuration of each object. I do not know if there is any way to avoid the ID error already registered and that the tool keeps the "state of the objects" after closing it and reopening it again, because I put the id = nil in each object.

 

...

 

On the other hand, I have done collectgarbaje tests with other tools. For example, Duplex returns 18688.289  KBytes (approximately 18.6MB). VoiceRunner 1437.452KB (1.43MB). If a tool generates <20MB, it seems reasonable. From 1 to 5MB it seems a pretty low figure. 

 

On the other hand, a tiny delay when loading Renoise is acceptable if after, the tool is loaded very fast (to open it). In the first case, the tool is executed instantaneously, since everything is loaded in the memory. The second case, there is a slight initial delay. Then, I come to the conclusion that it is convenient to use the memory depending on the use of the tool. If each time you start the tool you have to have an identical object state, the second option is appropriate. If you intend to keep the state of the objects for the duration of the entire Renoise open session, the first option is better.

 

I need to define with many ID's a multitude of objects, in order to change their state (color, bitmap, text, etc.). Then it is not advisable to cancel the id previously to reload it again. So I do not know how to merge the two cases, so collectgarbaje return the minimum amount possible (I think it will be around 500KB) and at the same time do not lose the state of the objects when closing and reopening the tool in the same session of Renoise.

 

All this is a little messy for me yet...


:excl: Development of my tools: Piano Roll EditorKangarooX120SamRenderPhraseTouch

 

:excl: My API wishlist R3.1 (updated 24 July 2017):

Spoiler

 

:excl: My Renoise 3.1 wishlist (updated 26 September 2017):

Spoiler

#9 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1862 posts
  • Gender:Not Telling

Posted 06 July 2018 - 17:07

Ah, good to know.

Here is one of the better concepts on how to build GUIs. You can use a class to separate the gui from logic and make it more readable, maintainable and reusable. Just for inspiration :) This kind of structure makes everything very easy to access. You could have a parent App class that is passed into the AppGui class (via args), for example.

Spoiler

Edited by joule, 06 July 2018 - 17:16.