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