Re: metadatabase

Ed Sweetman <[email protected]>
Newsgroups gmane.comp.audio.zinf.devel
Message-ID <[email protected]>
David Hough wrote:
> On Wed, 15 Oct 2003 10:37:00 -0700, Kristian Kvilekval 
> <[email protected]> wrote:
> 
>> On Wed, 2003-10-15 at 10:18, David Hough wrote:
> 
> ...
> 
>> Again how would this co-exist would recursive playlists?
>> Should the current index be of the entire expanded list?
>> Just to be clear the player has it's own idea of a what
>> a playlist is.. The current UI may have several playlists,
>> only one of which needs to be consistent with the player's.
>> For example:
>>
>> Player playsheet
>> 1.  file://song1.ogg
>> 2.  file://myfavorites.m3u
>> 3.  zinf://url?genre=ambient
>>
>> While the UI may show:
>> 1.  file://song1.ogg
>> 2.  +file://myfavorites.m3u
>> 3.     file://song2.ogg
>>         ...
>> 99. +zinf://url?genre=ambient
>>        file://song10.ogg
>>        ...
>>
>>
>> The concept of index may not make too much sense
>> if we allow this.   However, URL's do not and should
>> not need to be unique (though I have seen a request
>> that there be option in the playlist to ignore
>> additional adds of the same song).   I am beginning
>> to think that a position should be a pair
>> (playsheet, index) or even modelled on a tree path.
>>
>> Any ideas?
> 
> 
> I think the tree path is probably the best idea as abstractly thats a 
> reasonable model of what the playlist would actually be like if you 
> started allowing items to be expanded.

I think the only way to do recursive playlists even remotely well is to 
have the Playlist object like this.

A playlist object contains a vector list of playlist objects, a string 
and a Metadata object.  The vector list of playlist objects is a pointer 
that is newed when the URI is a playlist or sublist.  The string is a 
std::string of the URI and the metadata object is a pointer that is 
newed when required. (it is NULL when the URI is a playlist).

Now the player sends a URI to the playlist manager to load the playlist. 
  The playlist loader interprets the URI to see if it's a file or a 
regex.  Either way it reads in the URI's either in the file or returned 
from the regex.
So now your top level playlist object is created with a new'd vector 
list of Playlist objects and the URI filled in with what the playler 
sent to the PlaylistManager. URI's that are not playlists are added to 
Playlist objects (one for each file) with the string and metadata (if 
required) filled in but the vector list of playlists left at NULL. This 
playlist object is then added to the Playlist object above it. If it 
reads in a regex or another playlist, the playlist object that is added 
to the playlist object above it has nothing in the metadata member, but 
instead new's the vector list of playlists and sets the string URI 
member and works over again recursively. When done with the lower level 
lists, it returns back to the upper level and the upper level continues 
where it left off.  A simple check to make sure an included playlist or 
regexp is not the same as any already added can kill infinite recursions.

This way it's easy to create recursive playlists with no special 
treatment, easy to detect when a member from the the playlist is not a 
stream but instead a sublist and makes manipulating sublists independent 
of manipulating the rest of the list.  It also allows you to move around 
entire sublists as a single element, and can even let you move items 
from the sublist out to other parts of the list with relative ease.

Note, the playlist object is not the Playlist Manager nor 
MetadaManager.Also, the top level playlist object is merely a single 
element of the master list. Which is again a vector of playlist objects 
but this vector can not be manipulated directly by the user and objects 
in it are added and removed by adding or removing active playlists. Thus 
allowing multiple macro playlists each having an arbituary number of 
micro playlists inside them, even giving the playlistManager powers to 
have playback loops dependent on any given selected playlist element 
range, including sublists in which the user selects the regex or 
playlist that is part of the larger list, and the playlist manager tells 
the player to play all the files in those sublists.



Ex.

This would be somewhere in PlaylistManager

Given the master list vector<Playlist> masterlist;

We load a playlist into an empty master list. Something like currentlist 
being loaded on boot. curlist is a pointer to masterlist[0] which is a 
vector of playlist objects. We now scan the file and add entries.

&masterlist[0]  would be sent as an argument to Populate which is our 
recursive function for populating adding elements to a list.  This will 
work for both single elements or regex's or playlists added to the list.
getElement always returns a Playlist object even when no matches are 
found, Such a match returns a "NONE" in the URI and NULL's for the 
metadata and playlist vector.  This would happen when the list is not 
yet done but no matches have been found for an entry (missing file or 
invalid regex).  "END" would be returned if the list either the playlist 
gave or the regex gave has been exhausted.  These two playlist objects 
are not added to the list, but rather used as markers

getElement is responsible for new'ing the vector<Playlist> *playlists 
member object of Playlist.

class Playlist {
    public:
        Playlist() : URI(""),Meta(NULL),playlists(NULL) {;}
        Playlist(const Playlist &cop) { copy(cop);

        std::string URI;
        MetaData *Meta;
        std::vector<Playlist> *playlists;
    private:
        void copy(const Playlist &cop);
};

in something like Playlist.cpp

void Playlist::copy(const Playlist &cop)
{
    URI = cop.URI;
    if(!URI.compare("NONE") || !URI.compare("END"))
       return;
    if(cop.Meta != NULL){
	Meta = new MetaData(cop.Meta);
    }
    if(cop.playlists != NULL){
       playlists = new vector<Playlist>(cop.playlists);
    }
    return;
}


int Populate(Playlist *curlist){
    bool done = false;
    while(!done){
       Playlist *temp = new Playlist( getElement(URI));
       if(!temp->URI.compare("END")){   // We finished the sublist
          done = true;
       else if(temp->URI.compare("NONE"){  // There was a match
           curlist->pushback(*temp);       // Add match to vector list
           if(curlist->end().playlists != NULL){
               Populate(&curlist->end());
           }
       }
       delete temp;
    }
    return(0);
}


> ...
> 
>> Whether loading the database is noticible if *very* dependent
>> on the machine you are running on.   My dually 1.8Ghz athlon
>> at work doesn't seem to mind loading it.  My 466Mhz P-III
>> chokes on it for 20-30 seconds everytime I opened a new browser
>> (old design).   The important thing is that loading
>> of metadata should not be noticable.   Let's leave the
>> decisions of what should be loaded and when it should
>> be loaded in the database modules themselves.  For example,
>> look at the implementations of mdb/gdbmdatabase and mdb/mkdatabase
>> The gdbm needs to preload the entire db in order to support
>> advanced queries..  You could change with a line or two
>> to cache the entries only on the first query.
>>
> You say that the big hit in performance was when opening a new browser. 
> As far as I could ever tell the database was only loaded once, then 
> cached. If this is the case then the real drop in performance was 
> actually due to all the processing required to create the GTK tree 
> (which does indeed take a lot of time) and didn't actually have anything 
> at all to do with how the database was read from disk. You never know, 
> perhaps the old database wasn't actually that slow and it was the 
> browser that was the real problem.
> 
> David
> 

The database wasn't slow.  There was a time when there was a bug in zinf 
that caused loadtimes to be extremely long but that was fixed without 
changing how the database was loaded. This was done in parallel with the 
lazydb work and basically removed the need for it altogether.





-------------------------------------------------------
This SF.net email sponsored by: Enterprise Linux Forum Conference & Expo
The Event For Linux Datacenter Solutions & Strategies in The Enterprise 
Linux in the Boardroom; in the Front Office; & in the Server Room 
http://www.enterpriselinuxforum.com
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.