I was running into a situation where new tracks added to a playlist were
showing up even if they didn't match the current filter text. Let's fix
this by refiltering the current playlist when new tracks are added to
it.
Fixes#114: New tracks added to filtered view
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Dragging onto a sidebar row without a valid playlist will prompt the
user to create a new playlist. I could probably add a "New Playlist"
row at some point, but this is easier for now :)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We only support drag-and-drop one row at a time, even though multiple
rows can be selected in the treeview. If this is a problem, then we can
figure it out later!
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This will be used for drag and drop, so that we can figure out what
playlist tracks are being added to.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We can just pass 0 to the sorted function to indicate that the playlist
shouldn't be sorted by default. Let's also take this chance to rename
playlist_generic_init_sorted() -> playlist_generic_init()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
If we have two albums by the same artist in the same year (such as a CD1
or CD2 postfix), then we'll end up mixing them together when sorting.
Fix this by changing the default sort order to
Artist -> Year -> Album -> Track Number
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The popover is shown whenever the user pauses manually with automatic
pausing enabled. This will give the user a chance to disable pausing if
it is no longer needed.
Implements #113: Cancel "pause after" configuration when user manually pauses
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We have to disable the up and down buttons when typing in the entry in
case the user decides to type a minus or plus sign.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I set the "linked" property on the hbox to make everything look like a
single widget. I'm doing this on my own to cut out the GtkAdjustment
and to just use the counter in the audio layer in its place.
Additionally, this will give me the ability to use "+" and "-" keyboard
shortcuts to activate the widgets.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This will be needed by the gui to find the current count at any time,
without waiting for a callback.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise we might crash when we attempt to look at ar_tokens[0].
Reported-by: Josh Larson <themutatedshrimp@gmail.com>
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The readd(), readu(), and readhu() functions are all used to read
various forms of integers. The readl() and readw() are for reading
either lines or individual whitespace-delimited words
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I rename cache_file_write() to file_write(), and implement the
corresponding file_read() for binary data.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I also take this opportunity to add a OPEN_WRITE_BINARY mode to support
writing binary data to files.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function currently only supports opening files for reading, but it
will soon be expanded to supporting writes as well. To support binary
reads, I add a new OPEN_READ_BINARY open mode.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'll eventually want to support text and binary files in both locations,
so cache files might need access to this too.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This change means removing cache files is now supported. As a bonus,
we try to remove empty subdirectories to keep down the clutter.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This might also be useful for cache files to track their current state.
To help with accurate tracking, I take this opportunity to add a CLOSED
state that files default to.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I also introduce a "file_operations" struct that will be used in the
future to do slightly different things for cache and data files.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And rework the init functions at the same time to reflect that data
files can now be placed under a subdirectory.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'm going to create a unified struct file that should be able to share
code between data and cache files. The first step is to push the old
structure to the side so it can still be used in other places.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I eventually want to make these fields const in the file code, so we
need a different way to manage and eventually free these strings.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We can only rename user-created playlists, so let's not even show this
option for the other playlist types.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Normally GTK will take care of this, but we'll need it for the
right-click menu so we might as well implement it.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This gives me a function that I can reuse in the sidebar right-click
menu, and it cleans up the main keypress handler so more keys can be
added.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This seems like a useful function to have, and we already need it for
deleting playlists. Let's make it a real function so we don't need to
duplicate code.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Enabling this option resolves several "Negative content width" warnings
that I was seeing. Normally I'd just ignore them, but these were
generating SIGTRAP during testing and causing the tests to fail
unnecessarily.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
If multiple paths are passed, then only load the first one to keep
things simple.
Implements #102: Allow outside tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
If a matching track isn't found in the track database, then use the new
track_alloc_external() function to allocate an external track with the
correct tags.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
There might be rare occasions where users want to play a track that
exists outside their music library. This patch adds support for
allocating and freeing these external tracks without adding them to the
track database.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'm struggling to come up with a good way to combine code for this with
code for track_add(), since the lookup mechanism is basically the same.
I'll keep them separate for now and think on it some more.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
It's possible that the user may pass us a subdirectory of a path that
has already been added to the library. We can use this to prevent
double-adding tracks if the user does this. Additionally, this function
can be used to help look up tracks using only a filepath.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I want to use this to prevent users from adding a subdirectory of a path
that has already been added to the library.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Let's just do everything inline and cut out the extra function calls to
make the code simpler. I also created functions to help tests send EOS
or error messages.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And use these to trigger the state changed callback. Additionally, this
callback can now be used by tests to determine when we're done seeking.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We only play local music, so we know that we're using a file and we
don't need a uridecodebin to figure it out for us.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Add some whitespace to make it easier to follow what everything is. I
also rename audio_bus to audio_old_id to make it easier to add in a new
audio bus. Additionally, I changed test_audio_player() to
test_old_player() to make room for the new pipeline.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I want to run a main loop during the audio tests, which aren't in gui/.
Let's rename this file to make me feel better about using it :)
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
A single middle click could happen by accident, especially if the user
has a touchpad. A double click is more likely to be deliberate.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Instead, watch for a middle click and set the editable state manually
from there. This fixes a bug where double clicking on a user playlist
put us in editing mode instead of selecting the playlist for playback.
Fixes#110: Cannot select user playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I want to be able to change this when the user middle-clicks a row, so
let's start by adding in some support functions.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
If we don't, then the Collection playlist will include hidden tracks
when it initializes.
Fixes#109: Hidden tracks showing up in Collection
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We use this to set the playlist name in the provided GtkEntry, clearing
out the number of tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The GtkTreeView editing callbacks give me a path string that I'll need
to convert into an iterator to find the edited playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Once we change the name of a playlist, we won't be able to find it in
the sidebar model. So let's add a way to update an iterator by passing
the playlist to use for updating.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Users may make typos in naming playlists, or they might think up better
names for playlists later. Let's be friendly and give users a way to
change playlist names if desired.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This saves ~75MB in my testing, and can be a useful memory savor for the
case where all album art has been downloaded.
Implements #96: Allocate g_thread_pool as needed
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This way we don't need to keep including the same core libraries in
almost every file.
Implements #83: Include useful headers in core/core.h
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The core_init_data only held three items, most of which don't get set
during testing. Removing this struct means several tests no longer need
to define a "dummy" initdata object to pass around during init.
Implements #92: Remove core_init_data
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And make them optional, that way tests don't need to keep creating fake
callbacks if they don't need anything from the audio layer.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Passing this option tells Ocarina that it should only process
synchronous idle tasks, such as library or playlist updates. This
effectively disables album art fetching (and any async jobs we add in
the future).
Implements #91: Add --no-fetch option
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Rather than offering two init functions for testing. This lets the UI
select if they want async idle tasks (like Album Art fetching).
Implements #90: Give idle_init an async flag
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Users might not remember any sorting or random settings from the last
time they queued tracks, so saving these values could result in
selecting tracks in an unexpected order. Fix this by resetting the
queued tracks options whenever the playlist is emptied.
Fixes#108: Unset random and sorting when finishing queued tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
These fields were working fine for statically initialized playlists, but
they get set to garbage values when g_malloc()-ing a playlist. Let's
make sure they get initialized properly with the rest of the playlist.
Fixes#107: Initialize all values in playlist_generic_init()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Everything has been merged into the playlist layer to better match how
playlists are actually used. This means we can remove the queue files.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Artist and library playlists are allocated manually, so there should be
generic functions that both can use to get a playlist pointer and free
it when we're done.
I also add a callback for telling the UI when new playlists have been
allocated. This isn't needed for Library playlists, but this is the
only way the UI can know about new Artists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Sometimes we want to initialize the playlist with sort data, other times
we don't. This gives us functions we can call for both!
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And change its type to gchar **. This lets the playlist code manage
setting and freeing search strings. The UI is still responsible for
how this string is used.
This patch also lets me remove the now-unused queue_deinit() function
and associated callback.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Storing the current link from the playlist should give us immediate
access to the track, rather than needing to use playlist_at() all the
time. Additionally, we can now use g_list_next() whenever we need to do
a gtk_tree_model_iter_next()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The iterator only needs to point to the current position on the GQueue,
so we can do away with manual position tracking. This lets us use a
GList pointer as an iterator instead of something more complicated.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I keep using the queue_iter struct for now to reduce code churn in this
patch. I'll be replacing it in the next patch.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I also take this chance to add extra functions for directly manipulating
the current track, since this is something we do fairly often.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function adds a track directly to the front of the playlist,
without any existence checks. This lets us use it for the History
playlist, which allows multiple tracks.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I can reuse the "removed" callback to for this, rather than implementing
a new "cleared" callback directly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We can make use of g_queue_find() to find the track for us, and then
convert its return value into a boolean.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Rather than iterating over the entire playlist ourselves, we can instead
use the g_queue_remove_all() function to do most of the work for us and
then send an appropriate number of "removed" callbacks.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function simply triggers the "updated" callback for the given
playlist and track. I updated the gui model to handle taking tracks
instead of row indexes, since this lets me reuse the same for-each
function that we do for sorting. Additionally, this prevents UI updates
for playlists that aren't currently visible.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I move the random variable into the playlist code since it is no longer
used by the queue layer. This gives me the opportunity to change it
into a boolean rather than a bit flag.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Let's have the playlist generic functions pick the next track rather
than redirecting to the queue code.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
In most cases this function just triggers a UI update, but system
playlists have a little extra bookkeeping to do to remove the track from
the Queued Tracks playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function is called to force-sort the playlist. Additionally, we
trigger the "playlist-sorted" callback to to notify the gui that
playlist rows need to be updated.
Additionally, I implement the gui_model_update_all() function to loop
over the model and update all rows of the current playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This replaces the "reset" field that had been passed to sort. I think
this makes things a little more straightforward, and gives us a function
we can call when freeing playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function uses the playlist save flags enum to determine what
exactly to save, including support for backwards compatibility with
6.4.x playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function uses the playlist save flags enum to determine what
exactly to load, including support for backwards compatibility with
6.4.x playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I renamed "type.h" to "playlist.h" to better match what it does.
Additionally, I moved generic playlist functions into a new header file.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This lets us call playlist_played() whenever we change tracks to send UI
updates once, rather than using multiple updates to change playcount and
now-playing status.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
It isn't needed now that playlist differences are handled in the upper
layer. This also lets me create a shared set of operations for dynamic
playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This was only used by system playlists to keep the unplayed, most played,
and least played playlist up to date. We can handle this internally
through the playlist_played() handler.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is used to notify when tracks have been played so dynamic playlists
can be updated, and so the model can display the correct playcount.
The old system playlist tests are mostly unnecessary at this point, so I
remove them as part of this patch.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Allowing us to access the playlist directly, rather than going through
the playlist-type interface.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And stores it for future reference, so we don't have to keep looking up
current and previous playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is much more straightforward than converting an id to a name and
then looking up playlists from there. This patch removes the now-unused
playlist_get_name() function.
This patch also lets me simplify the system playlist unit test, since I
can now check several similar operations using a loop. Additionally, I
change calls to pl_system_lookup() into pl_system_get() for efficiency.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I think "lookup" is a better name for this function, since it's similar
to performing a dictionary lookup.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Additionally, it also uses a playlist-level function pointer to decide
what to do. In most cases this calls the generic sort function, but the
history playlist should never be sorted.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Additionally, playlist_set_random() uses a playlist-level function
pointer to decide what to do. In most cases this will simply toggle the
flag, but the history playlist does not support random playback.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Rather than going through playlist-type operations. Additionally, I
take this opportunity to change playlist_remove() to take a playlist
struct directly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Rather than going through playlist-type operations. Additionally, I
take this opportunity to change playlist_add() to take a playlist struct
directly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Rather than going through the playlist-type operations. Additionally, I
take this opportunity to change playlist_delete() to take a playlist
struct directly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is much more useful than a boolean status, since we can use the
playlist pointer right away.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
It's frequently useful to get the playlist directly, rather than looking
up type and name first. Let's add a function to do just that!
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This pointer can be used immediately by testing code instead of simply
looking at the return status.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is useful for user playlists so they can store their playlist-id
directly, letting us remove the entire playlist_get_id() function.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This flag was only used by the History playlist, but we have a noop
function to handle this instead.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise we could end up changing the random setting on the previous
playlist when displaying a new one.
Fixes#106: Switching playlists clears random setting
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I cleaned up several of the functions and added tests for making sure
everything is set correctly.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This patch also adds a unit test checking that the image is initialized
properly. In addition, I simplify things by changing the image widget
to be a direct child of the GtkButton.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This keeps all the audio operations together, and matches how we define
operations structs throughout the rest of Ocarina.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This code is obsolete now that gui/playlist.c handles keypress and
right-click events on the main treeview.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function isn't easy to test without knowledge of screen
coordinates, so I didn't include a unit test this time.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Looks like this wasn't happening automatically, so let's be sure to
update the previous playlist's row after selecting a new playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Putting this code in a new file helps make gui/playlist.c less complex,
and better matches the organization of files in core/
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Finding the header first makes a lot of sense, and avoids iterating
through every playlist while trying to find the library playlist to
update.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This functionality needs to be tested better. I can't really test the
dialog, since it runs in the main thread, but I can test adding library
paths with the selected directory.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This code is obsolete now that the sidebar handles setting the random
button when playlists are changed.
Implements #76: Remove struct gui_queue
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Gtk doesn't have a simple way to manually trigger this, so I didn't
write a unit test for this feature.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function scans through the treestore at the current level, without
descending into children. This is because we frequently know what
category playlists are under when searching for a child, so it makes
sense to find that first.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Called to access the GtkPaned widget. I also rename the widget
"sidebar" to match the new convention.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise we may try to use the gstreamer playbin after destroying it,
leading to various error messages showing up in the console.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This will open up each of the playlist headings except for "Collection",
which I think is the behavior we want.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise we'll get a message saying that either the filter or the
treeview is not a GtkTreeModel
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The concept of queues is going away over the next few releases, so we
should rename this variable for consistency. I considered calling it
"playlist_model", but I think "gui_model" better matches naming
conventions in the gui.
Imlements #77: Rename queue_model to playlist_model
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I connect this in code so I can pass the column index as data to the
function, avoding the need for a "column index" lookup function.
I restore saved column widths during startup.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I decided to manually connect signals this time so I can pass sort
information instead of needing to look up the column index.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And rename the widget from "o_treeview" to just "treeview".
I wanted to rename gui/view.c to gui/treeview.c at some point. I
decided to gradually rework things into a new file to make it easier to
track progress.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This keeps the treepath conversions contained to the filter code when
finding paths to scroll to.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Right now filtering is split between queue.c and view.c, which can make
things somewhat complicated. I think this is a sign that we need a new
file to manage filtering.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Ocarina is moving in a playlist oriented direction, so move away from
using the queue directly in favor of using the playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This only needs to happen once, so let's do it when we initialize the
model rather than waiting for the first allocation.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is going to represent a playlist soon enough, so let's just name it
something more generic in case it ever has to change again.
Implements #87: Rename GuiQueueModel -> GuiModel
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is cleaner and easier than calling into the gtk builder directly.
I bumped up the window layer so other gui components can use it.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is called to get the requested playlist. I also reworked
playlist_get_queue() to call this function.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The function gtk_menu_popup() is deprecated as of Gtk 3.22, so replace
it with the simplified popup_at_pointer() function.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The new file is written in the Gitlab markdown language. I also update
the content to match how things are done now that we use CMake.
Implements #85: Update README
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Track database defragmenting can happen before the new tasks are ever
scheduled, causing a crash when we try to find tracks with changed IDs.
After the crash, the Favorites and Hidden playlist data appears to be
lost.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We want playback to continue after the queued tracks playlist has run
out. Allowing us to select the same playlist multiple times can cause
us to get stuck picking the next track.
Fixes#100: Finishing "Queued Tracks" playlist shouldn't stop playback
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise we will crash with a memory error. This only seems to be a
problem when Ocarina is started up after creating a user playlist.
Fixes#99: Ocarina crashes during startup with user playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We need to free the playlist name after looking up in case we hit the
case where the playlist isn't found.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise valgrind will report that we are leaking memory.
Additionally, only initialize the idle queue for sync idle tasks until
album artwork needs it.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Valgrind told me that all calls to g_assert_cmpstr_free() weren't
actually freeing the string. A closer look shows that if we pass a
function as "lhs" then the function will be called twice, allocating
twice as much memory.
Fix this by storing the result of lhs in a temporary variable so
functions are only ever called once.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This makes the flag a little easier to toggle for testing. I also
rename the compiler option for consistency.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
__gui_playlist_init_idle() will select the first visible playlist by
default, which is what we want. Let's not override this by showing the
Collection later in this function.
Fixes#95: Startup shows Collection instead of Queued Tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I find that I usually create playlists through either a right click
action or through a keyboard shortcut, so we don't need an extra option
hidden inside a MenuButton. Let's remove the button and show the "Add
Library Path" option directly instead.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This lets up update track keys to prevent duplicates showing up during a
library path update.
Fixes#93: Library sometimes has duplicated tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Sometimes database entry keys change, so this gives us a way to update
them in the database keys hash table.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This fixes a problem with restoring treeview columns. Sometimes
"Played" gets allocated way too much space, so I solve this by changing
it's setting key to NULL so the column always gets whatever space is
leftover.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
NoWheyCreamery.com doesn't run an Xserver, so we can't run UI tests.
Add a switch to disable these so test results can be reported
accurately.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
These options are mostly used to communicate with a running Ocarina
instance to control playback.
Implements #37: Ocarina Command Line Commands
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This playlist has been the same as the hidden playlist for several
releases now. Let's make the change official!
Implements #28: Save hidden playlist as "hidden" instead of "banned"
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
One word labels are always better. I move the "Favorites" and "Hidden"
playlists under the "Playlists" header because they're manually
configured by the user.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Rather than waiting for them to load with an idle task. This speeds up
Ocarina startup dramatically, since playlists can be added to the UI
with the correct size instead of needing extra callbacks to update the
size each time a track is added.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This was added so tracks could bump the libary tag size. Now that the
size field has been removed, we can remove this function.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The convention is for gtk builder files named with a ".ui" extension.
Let's rename our file to match, and drop the 6 while we're at it.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This makes file versioning way easier, since every file will have the
same version. I'll still need to manage minimum-supported versions, but
that shouldn't be too difficult going forward.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
These can be used for version number comparisons as integers, which will
be useful once file version numbers are based off of minor versions.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Most playlists don't allow changing this, and now that we have user
playlists it doesn't make sense to support repeating queued tracks.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This has to be created programmatically due to the dynamic nature of
user playlists. The easiest way to do that is to list user playlists in
a submenu and switch them out as needed.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This lets me "pause" playing queued tracks in favor of other playlists.
I remember the previous playlist so we can resume track picking once the
queued tracks playlist is empty.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This lets me add new options without needing to clutter the gui with
lots of rarely-used buttons.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Databases can change either as part of an upgrade or through adding and
removing entries. We can save a bit of memory by removing unallocated
entries during startup.
Implements #47: Automatic database defragment
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This was used to display the number of tracks in each library path. We
can use playlist functions to get this information now.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This was used to enable and disable library paths in previous Ocarina
versions. This isn't used anymore now that we have library-based
playlists.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The track tag doesn't need these tags now that they can be found in the
album tag.
Implements #64: Remove Artist and Genre pointers from Tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Artist and genre information are already saved by the album tag. In
addition, we can save a single date stamp instead of (year, day, month)
triplets.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And perform an upgrade when reading back in. After track tags are read,
we can save the database in the new format and remove the old tags.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
And propegate these through the alloc steps to create an album with the
correct artist and genre tags set.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This allows for representing albums with multiple genres. I know this
doesn't happen too often, but it doesn't hurt to be covered. At the
very least, now we have a genre id for constructing new albums!
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I need a way to represent the same album with different artists to
account for multi-artist albums.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The date stamp is a single value that represents year, month, and day.
This should be slightly easier than working with three separate values.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Removing items from the database leaves a NULL pointer "hole" that is
never filled in. This doesn't affect correctness, but it could be
wasteful as items are added and removed. This patch adds a function to
defragment the database without changing the order of items.
Implements #66: Add support for rebalancing databases
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I plan to change the file format of some tags, so add versioning so we
can change things at different times.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is needed to handle track database defragmentation, but could also
be expanded on later to save playlists from a generic place.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This prevents double-saves in both the playlist entrance function and in
the overridden function.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This function loads playlist information from a single file, falling
back to multi-file loading if playlist.system doesn't exist yet.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I need to disable filtering when adding artist playlists to avoid some
weird memory corruption issues.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I intend to use this to hide empty playlists, but it could potentially
also be used to search for a specific playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I query the underlying playlist to see if it is selectable, and then
update the settings file if it is.
Implements #10: Select default playlist
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I need to have integer playlist ids to store into the settings database
once I allow changing the default playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Right now tracks are picked from this playlist whenever possible. A
system for selecting the default playlist will be added shortly.
Implements #20: Only one queue for "Up Next"
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The settings code is designed to map strings to unsigned integers, which
is exactly what we do here. This lets us cut out an extra file access,
which is always a plus. We remove the audio file after upgrading to
prevent reading it multiple times.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The playlist code is heavily tested by unit tests for the files in
core/playlists/, so we no longer need to have a separate playlist test.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I initially tried making several helper functions to reuse code and make
it easier to add new playlists. This didn't work all that well, mostly
because glib wasn't able to expand variable values or find the line
number that errors occured on. Macros don't have this problem, since
they are expanded at compile time.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This test can take a long time to run, especially on slow internet
connections. Let's add a way to disable it when testing other things.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This changes test output slightly, in that files are now placed under
subdirectories of $XDG_USER_DATA_DIR/ocarina-test/ instead of in this
directory directly. This should help avoid conflicting files, and lets
me use a single "rm" command to remove everything before testing.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
For using cmake to generate a makefile instead of building through
scons.
Implements issue #3: Investigate CMake
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Unplayed, Most Played, and Least Played tracks playlists update
themselves with an idle task when tracks have been played. It looks
like we haven't been processing these tasks, so the queue was just
building up after every track. Fix this by enabling the GTK idle
callback whenever a track is played.
Fixes#89: Dynamic playlists aren't updating
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The view is now responsible for allocating the filter, but the gui_queue
still needs to set the filter function during an init step.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Now that we can switch between different queues we no longer need to
allocate multiple models.
Implements #72: Only allocate a single GuiQueueModel for all playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We can cut out several thousand function calls and allocations by
reusing the same GtkTreePath structure.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The dbe_index of a given database item might change in the future, so we
can't rely on it everywhere. Let's just use it for saving and loading
files, with the expectation that changes will happen sometime after
startup.
Implements #69: Reduce use of dbe_index in Ocarina code
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Three unsigned integers is overkill for handling dates.
Implements #65: Date structure can be represented with a single 32bit
value
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Albums tend to have a single genre for all tracks, so it makes more
sense for an album to point to genre information.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This isn't as important for established playlists, but this string could
quickly become an invalid pointer for new playlists that are added.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This gives users the ability to add new library paths by pressing the
"Enter" key instead of needing to click a button with their mouse.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Most users will have their music in their ~/Music directory, so it makes
sense to select this path by default.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
- Define __queue_filter_how_changed() for tests that need queue
callback functions
- Increase column sizes in the view test to make test more reliable
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Library playlists call this when deleting tracks, otherwise we could end
up dereferencing invalid pointers the next time we use the artist
playlist.
Fixes#81: Remove deleted tracks from artist playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This patch also adds the genre field to the list of fields that can be
searched.
Implements #62: Replace filter layer with token matching
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is called to check if any string in an artist's token list is
prefixed by the given string.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is called to check if any string in an album's token list is
prefixed by the given string.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This will be used to replace the current filtering code with a token
comparison for each track.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is easier to maintain than a giant switch statement, and should
make it easier to add new playlist types in the future.
Implements #61: Clean up system playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The history playlist uses a noop function, since changing random or
repeat settings doesn't make sense for this playlist. The collection
playlist uses a custom function to save changes after setting a flag.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I set the history playlist to use a noop function, since changing the
history doesn't really make sense.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm hitting this problem while developing 6.5, since file formats are
going to change. Let's handle this situation gracefully rather than
segfaulting.
This patch changes versioning problems into fatal errors to prevent us
from overwriting data already on disk.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We only need to do this after Ocarina init has completed, otherwise
artist playlists will be added twice.
Fixes#79: Artist playlists not updated when tracks are added
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Scanning new library paths should also add artist playlists, otherwise
they won't show up until Ocarina is restarted.
Fixes#79: Artist playlists not updated when tracks are added
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
We were calling the queue function directly, rather than passing through
the playlist layer. This means random state isn't saved when the button
is clicked and Ocarina is closed.
Fixes#78: Call playlist_set_random() when clicking random button
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
But only if the library database is empty. This patch also changes the
prompt of the dialog to "Add Music" so users know what is going on.
Fixes#80: Pop up FileChooserDialog the first time Ocarina is run
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This seems less efficient overall, since we now need to take several
passes over the track database. What I've noticed is that the
single-pass option creates a lot of UI notifications that makes the gui
unresponsive for a large amount of time. Breaking this into smaller
chunks gives us a chance to handle any user actions between loading each
playlist.
Fixes#71: Initalize artist playlists with more idle tasks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This is easier than responding to events from the treeview. Let's just
pop up a dialog and let the user select from there, rather than doing
something complicated with a stack.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
System playlists cannot be deleted, but library playlists can. Deleting
a library playlist removes the library and associated tracks from the database.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The pl_artist_init() function is used to allocate a playlist for each
artist already in the database, and pl_artist_deinit() is then used to
free up this memory during cleanup.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
System playlists cannot be created or deleted, so these functions simply
return false in this case. Library playlists will use this to add new
library paths to Ocarina.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also take the opportunity to add in a generic lookup function to
convert a library path into a playlist.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function is for both adding and removing tracks, and only returns
false. Tracks will only be added and removed through the update
function.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The pl_library_init() function is used to allocate a playlist for each
library path already in the database, and pl_library_deinit() is then
used to free this memory during cleanup.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Similar to the library tag, this is a void pointer that should only be
used by the playlist layer.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I decided to set this as a void pointer to keep other layers from using
the playlist without our knowledge. The only user of this variable
should be the playlist code.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm going to use this to distinguish between various playlist types that
are about to be added. Let's update the playlist functions first, and
then add more types in a future patch.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Otherwise the existance check will still pass the next time
__queue_filter() is called, and we will attempt to destroy it again.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I wasn't doing this, but I also wasn't refiltering queues when they were
changed. This resulted in showing a filtered queue, but without a way
to clear it. Remembering the text lets me simply set the text, instead
of refiltering queues whenever they are changed.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This preserves the original behavior, where the collection is always
selected from the beginning. This can be improved upon later, once
queued tracks are implemented as a playlist.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I'll need this to toggle the random flag for the Collection playlist to
avoid cycling through the GUI in order to save.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Containing the playlist name and queue. I pass this to the gui through
the queue_init() function.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It doesn't make sense to have a subdirectory with a single file. Let's
move it back to core/
Implements #45: Move database into core/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I think this is cleaner than having an upper layer allocate the results
set manually. This also lets me return NULL in the case that there were
no results.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I was storing database indexes, but this assumes that database indexes
are constant. I intend to change this with database defragmentation.
Implements #46: Filter stores a track pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is used to remove tracks from the filtering index. We'll need this
once we switch over to storing pointers to keep the same track from
getting added multiple times.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is more straightforward than using my custom index code without
adding too much work.
Implements #43: Filter code can use a GHashTable directly
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The thread pool is used to fetch album art in the background, but this
can slow down most tests that aren't interested in album art. Adding a
(testing-only) function for running without the thread pool speeds
things up a bit.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
The file filter and preview widget are both cleaned up when the file
chooser dialog is destroyed.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Sometimes Ocarina gets the correct image for CD1, but not for CD2.
Allow traversing into hidden folders so users can select the correct
image out of the artwork cache.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Otherwise the new image will never be updated due to the "did the album
change?" check in __artwork_set_pixbuf()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This lets users actually see images before selecting them for ablum art.
Implements #59: Add preview widget to album art chooser
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Using gdk_pixbuf_new_from_file_at_scale() can result in a blurry image
due to something in the gdk backend. I want to have a sharper image, so
we need to perform the scale manually through Cairo.
Fixes issue #60: Album art is blurry
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
Since MusicBrainz limits us to one request each second, it doesn't
really make sense to poll for new artwork every half second. Instead,
let's just put this into a new timeout function that gets called every
two seconds. This should also let us stop polling once artwork has been
found.
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
I intend to use this for creating playlists with different properties,
such as using the playlist interface to add library paths.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I want to manage this container on my own, rather than relying on the
generic index code. This will eventually make it easier to store a
playlist as a queue, instead of a set.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This flag is used for bulk inserts to cut down on the number of gui
operations during startup. Let's just make it standard that unsetting
the flag causes the queue to resort itself.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I plan to remove the containers/queue implementation, so we need a new
iterator for queue access.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I use this status indicator in the playlist code fairly often, so let's
return it directly rather than needing to code around it.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
If the user is fixing broken album art then we need to update the image
immediately, otherwise the user will be confused.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
- Allocate CaaCoverArt as needed, rather than sharing one object
- Use MusicBrainz fuzzy search to match more albums
- Escape most special characters in filenames
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Reusing the Mb5Query can have undesireable side effects, such as the
error code not getting reset between queries. Fix this by allocating a
new Mb5Query before evey request.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is needed so the user can manually set album artwork in the cases
where either we don't fetch the right image or no image is found.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I think this results in a slightly better search, although there are
still a few wrong images fetched.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
If searching for artist and album fails, then fall back on album and
year or even just album name.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Using gdk_pixbuf_new_from_file_at_scale() will load a scaled pixbuf,
which looks better than loading a height x height square.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Somewhere along the line the grid formatting got messed up, probably
after several merges while other bugs were fixed. This patch reworks
the grid so everything is formatted correctly.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I want to reuse as much file code as I can for cache files, but I need a
new struct since data and cache files track different properties.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I don't think it makes sense that callers of file_open() are expected to
check the file version after opening. This should be something handled
by the file code so we can print a consistent error message.
Implements issue #5: Better file versioning
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I want to be able to print any message as an error message without
relying on errno. Let's handle this by introducing REPORT_ERRNO() to
look up the right error message for a given errno.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
And then rename the temporary file when closed. This protects users
data in case Ocarina gets killed.
Implements issue #31: Make file writes seem atomic
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
There are enough differences in the read and write paths that
__file_open_common() was still trying to account for. Let's make a
simpler wrapper around g_fopen() and move differing code into
__file_open_read() and __file_open_write().
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm only setting this to a static string, so it doesn't make sense to
store this as a char array. Let's use a string pointer instead.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm going to use this for saving album art to the right place. I moved
it into an include file to avoid duplicating code.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The track database now tallys total play count and unplayed track count,
so we can use this information for calculating averages. I also changed
the least played tracks playlist to allow tracks with play count equal
to the average.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function returns the average count of tracks that have been played,
and not the average count of all tracks.
Implements #29: Efficiently calculate average play count of tracks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I no longer need these now that the queue is using the glib
g_random_int_range() function.
Implements #32: Remove custom RNG code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Using somebody else's library is probably better than relying on my own
random number function.
Implements #32: Remove custom RNG code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Load all tag databases with the new load function.
Implements #15: Load track database through an idle task
Implements #16: Load library database through an idle task
Implements #17: Load genre database through an idle task
Implements #18: Load artist database through an idle task
Implements #19: Load album database through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Scan over all tracks in the database first, and then schedule a
collection update.
Implements #13: Load collection queue through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This will help reduce disk accesses during thet main startup sequence.
Implements #12: Load temporary queues through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Let's save this disk access for when we're idle.
Implements #11: Load initial track through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch fixes two issues. First, I disable scrolling when the user
has manually selected a track. I've found that extra scrolling in this
case can be disorienting, and frequently ends up with the wrong track
selected due to how queue iterators are set so it's probably best just
to disable scrolling in this case.
This patch also changes the order of calls to set_cursor() and
scroll_to_cell(). I've found that scrolling before setting the cursor
causes the GtkTreeView to ignore alignment settings unless the row is
already on the screen. Switching the order makes everything work
properly.
Fixes#57: Wrong track is sometimes scrolled to
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch adds support for changing a rows font face to bold for the
currently playing track. This should make it easier to find what track
is playing while quickly skimming through the list.
Fixes#22: Highlight the currently-playing song in the collection
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I need to do this for temporary queues in addition to the collection for
bolding to work properly.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Otherwise the list of tracks is left blank, which the user might not be
expecting.
Fixes#55: Collection should be selected by default
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Cleared is only called during Ocarina shutdown, so calling save here
wipes out any temporary queues as they are written to disk.
Fixes#24: Temporary queues not saving
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Tracks information should always be the same height, so we can safely
enable this as a quick speed up to the treeview.
Fixes#52: Enable GtkTreeView fixed height mode
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The right way to do this would be to respond to the "activate",
"startup", and "shutdown" signals. I can't to this easily, because
gstreamer needs argc and argv. Let's fake things up now and sort it out
later.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
- Press "f" to add tracks to the Favorites playlist
- Press "q" to create a new temporary queue
- Press "r" to create a new temporary queue with Q_RANDOM set
- Press 0 .. 9 to add tracks to a temporary queue
- Delete to remove tracks from a queue
I also removed the corresponding keypress events from the C++ code to
make progress easier to track.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function is similar to queue_remove(), except the remove can be
prevented if qop_erase() returns false.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
We don't need different operations for each queue. If we store this
then a higher layer doesn't need to keep passing the same structure over
and over again.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Enabling all queues by default, even ones read from disk, is incorrect
as it leads to all queues getting reenabled when restarting Ocarina.
Fixes#56: Enabled status of temporary queues not saving
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm not even going to try converting my C++ code. Let's just start
fresh, and write unit tests as we build this up.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This gets cleared every time the queue is changed and disabled when we
show pages that cannot be filtered.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I need to change the state of these toggle buttons whenever the
sidebar's current selection changes. Some gtk themes have trouble
showing the state of toggle buttons, so I change the sensitivity of both
the button and associated image so users know the current state.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function is used to notify a higher layer that a queue is being
deinitialized. The higher layer should then clean up any state
associated with that queue.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function is used to notify a higher layer that a queue has been
initialized. That higher layer can return a pointer to be attached to
the "private data" field of the queue.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Most of the time people want to pause playback, rather than stop
entirely. Let's remove the button since it's not getting any use.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It's easier to have the controls expand into this column, but still
align them with the edge of the window.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This feature isn't used very often, and keeping the checkbox in the
sidebar looks pretty ugly.
Fixes#50: Remove Collection checkbox
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm surprised this wasn't already there. I think the "folder" icon
works best, considering library paths are directories in the filesystem.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is a UI tweak that I think looks nice. Future work: store the
expander position between sessions.
Implements #40: Add expander to playlist and collection treeviews
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It's easier just to set all images to have the same size, rather than
making the header's image slightly larger.
Fixes#39: Remove GtkIconSize from Playlist treeview
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also update the icon to match what is on the "Hide Track" button.
Fixes#49: Hidden playlist still says "Banned" in sidebar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I shrink it by a little bit to make the default ratio 10 x 6.
Fixes#42: Change default window size
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The xpad and ypad properties are deprecated, and this button looks fine
without anything set.
Fixes#41: Fix spacing on Add Selected Path button image
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm using multiple treeviews, but only one should be selected at any
time. Use this function to coordinate that.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Saving maximized state is too complicated, so let's just store width and
height of the window when it is not maximized.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I handle the Escape key through gtkbuilder, so let's move the
tab-changing keys into the tabs source file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I think this looks a bit better. I'm using an empty label as a spacer
between control buttons and text, but this can be replaced with album
art later.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Otherwise pressing the spacebar while searching could toggle the play /
pause status.
Fixes#36: Button accelerators always triggered
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I have tests running on ocarinaproject.net, which is headless and
doesn't run an X server. Gui tests cann't run without an X server.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
xfce does not seem to handle scaling icons on hidpi displayes, and I
configured everything based on really tiny icons. This can lead to
way-too-large icons on non-hidpi screens. If your DE doesn't handle
icon scaling properly, then you might want to consider running ocarina
with:
GDK_SCALE=2 GDK_DPI_SCALE=0.5 /bin/ocarina
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is better than calling audio_*() functions directly, since we can
make sure signals are wired up properly in glade.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The settings layer will track various configuration options set by the
user. This belongs in the gui, and not core, because it controls
settings specific to this gui implementation.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It's better to have a single function loading tracks and adding them to
the history queue.
Fixes#2: Initial track not added to history
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
6.4.8 changed how random tracks are selected, but never updated the unit
test. This patch fixes the unit test, and makes a few changes to make
sure the right tracks are getting selected.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The GUI needed an extra function to do this manually, which means it's
something that core should do instead.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This replaces the is_playing() function of the AudioDriver class. I can
also make the GUIs GstDriver static.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Dividing queue size by 3 seems to give a better distribution of tracks,
but only for a large set of tracks (such as the entire collection).
let's skip the division if the queue only has a small number of tracks.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
If the library isn't valid, then we shouldn't try to pick another track
until the user fixes things.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I was assuming that my disk returns -EIO when it enters its failed
state, but it really seems to be return -ENOENT. Let's have this code
check for any error, rather than one specific one.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm seeing Ocarina crash when a tempq finishes and gets removed. For
now, let's only have the gui handle queue clearing if tracks were
actually removed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I had the condition reversed for enabling random on temporary queues, so
the flag was getting set whenever I didn't want it.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
One of my disks frequently returns this error, and has wiped out my
track database on more than one occasion. Let's handle this error by
disabling the library until the user tells us it is safe to use again.
Fixes#33: Handle music directories disappearing better
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The first thing queue_deinit() does is clear the queue, so calling
tempq_save() here will overwrite any tempq state currently on disk.
This seems reasonable at first, but ends up erasing any temporary queues
during Ocarina shutdown.
Fixes#34: Temporary queues not saving
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
We were returning right away if the file version check fails, without
closing the file. This could cause future reads or writes to fail to
open.
Fixes#25: File version checking doesn't look quite right
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also take this opportunity to drop support for upgrading from file
format 0. I've had several releases since this format was supported, so
this should be safe to do.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I decided that having a uniqueue history queue doesn't really get me
anything, so I dropped that portion of the behavior.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I haven't referred to this in forever, and it's a few versions out of
date. I don't think it's needed anymore.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function is used to cancel all idle tasks and free the memory
allocated for them. This needs to be called when Ocarina is shutting
down to prevent a possible hang with the gtk idle callback continuing to
process tasks.
Fixes#30: Closing Ocarina should cancel idle tasks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
"Banning" a track is a bit harsh. Let's talking about hiding tracks
instead, so that it sounds friendlier.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Rather than doing this in two separate lines. Also drop the -j2
argument to scons to help with memory issues.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
GitLab CI failed on this test because the last remaining idle task was
the one to scan the new directory. Let's make sure we've run through
all idle tasks before continuing on with this test.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I created a new function for checking if a group of tests is running to
help determine if the sanity test needs to run before anything else.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I think it makes more sense to have the collection manage if banned
tracks are displayed or not, rather than doing this from the playlist
layer.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
There is at least one place in the gui where it needs to know if a track
was actually added to a playlist. Adding a return value is the best way
to know what happened.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is much more convenient to users, since they don't need to update
the collection manually.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch breaks later tests, since I needed to remove the old ogg
files. This will be fixed in a few more patches.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'll need a second album for testing collections, and Ocarina of Time
seems like the obvious choice!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I needed to bump the track comparison fields by one so I can use signed
values to indicate sort order. I updated core/library.cpp to add and
subtract one as needed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
These functions are only used by temporary queues, and the collection
queue has its own save function.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
And a function to help with saving queues. This patch also adds the
Q_SAVE_FLAGS and Q_SAVE_SORT queue flags to control if the queue should
be saved when flags are changed or when the queue is sorted.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch implements basic queue iterator functions for accessing
specific positions on the queue.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
We were opening a directory for scanning, but we never closed when we
were done. If we do this enough then the kernel starts telling us that
there are too many open files.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
From Josh: Single-clicking a track in the collection queue and pressing the
space bar loads the selected track, but users would expect this to
toggle the play / pause state instead.
The solution is to watch for the on_key_press signal and tell GTK that
we have handled it if we see that the space bar was pressed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
We now have an interface for controlling everything through struct
db_entry, so let's just have the database store a db_entry directly.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Track tags need to add themselves to the filter index and update the
library track count once added to the database.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The Track tag needs to do some cleanup when removed from a database, so
we need to use this op when removing items.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
For allocating new database items from a given key. Tracks do not need
this function since we have special handling for creation and insertion.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
gen_tracks.sh will read a specially configured file and create a
directory containing empty tracks to use for testing.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I replace the standard and copy constructors with one that tags a track
during construction. This lets me clean up a lot of code, and keep
tagging functions internal to the track class.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
We want to loop over the track database in several places, so let's make
this easier by just returning the database itself.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It's easier to just pass off the library database rather than forcing
higher layers to iterate over the entire thing (including possible
invalid entries).
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also have to replace the "library" namespace with the "collection"
namespace to avoid naming collisions.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function is similar to Linux's list_for_each_safe(), and lets you
iterate over a database even if the current item is removed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also take the chance to modify this function slightly. Now, if a
matching item could not be found a new item will be allocated.
I added the new function db_get() if callers just want to get an item
without allocating.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Finding an inline intersection is really easy using iterators, so I
wrote this function to modify one of the set rather than returning a new
one.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The glib library doesn't have a dedicated "set" container, so I need to
create a wrapper around a hash table to accomplish the same results.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
g_strchomp() modifies the string in place, but doesn't free up unused
memory at the end of the original string.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This helps improve filtering, since I drop all modifications to
characters (such as accents over an 'e').
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I noticed that tracks beginning with a number were getting combined with
the seconds field, creating an inaccurate seconds count and modifying
the title at the same time.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I eventually intend to remove the file_init() function, once everything
has been converted to C.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also introduced a file_readf() function to make it easier to read a
formatted string from the file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also introduced a file_writef() function to make it easier to write a
formatted string to the file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
And replace it with the function file_init(). Let's take this chance to
rework parts of the unit test as well.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This change also lets me remove the destructor, since code is expected
to call file_close() when IO is complete.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I only need one function to perform the entire conversion using
g_strdup_printf(). This helps to simplify the code before switching
over to C.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
And I replace it with a simple call to g_strdup_printf() that does the
exact same thing. Note that callers are now required to free the
returned string with g_free().
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I replace it with calls to g_strdup_printf(). This has the additional
benefit that I can do uint conversions at the same time as other
formatting options, so this seems like a win. The only downside is that
I have to manually free the memory that glib allocates, but that's easy
enough.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I converted the test to the new framework, and I introduced a new
"test.h" file in the source directory to help with mixing C and C++
code.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The version test is fairly simple, since it only tests the values set in
a single header file. The remaining tests will be more challenging,
since I'll have to modify core code and the test at the same time.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I commented out most of the file and directory modification code while I
was at it. I'll re-add these as I convert more files to C.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I want to make the scons files simpler, so I have decided to drop down
to only one test environment. This patch disables
tests/core/Sconscript, but I'll add this back in as I make other changes
throughout the codebase.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This lets them set themselves whenever values change. Additionally, I
update the Tab class to take a QueueLabel instead of the "size label"
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I can't pack it directly into the tab_vbox because playlists need a way
to pack in their special window.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
GtkBuilder doesn't let me pass additional parameters to classes
constructed with get_widget_derived(), so I have to use an init()
function for flags and other parameters.
This patch adds flags for which buttons to show on the queue toolbar.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I frequently hit a problem where playback stops when a track has an
error. My gstreamer code was written assuming that the pipeline stayed
in GST_STATE_PLAYING if there was an error, but I think this assumption
is wrong. For now, let's always restart playing on error.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I expect most of the new constructor code to disappear once I start
using the .ui files in the parent class.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm going to want this on all tab pages, so let's just add this to the
treeview widget definition.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This should help clean up the code a bit, especially once I convert all
queues to load with the template files.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The QueueView doesn't contain too much in terms of code, but the
corresponding QueueView.ui file lets me remove a lot of unnecessary
stuff from temporary queue creation!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm going to have a lot of queue-related files soon, so let's make
things easier by keeping everything in a new directory.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This release focuses on fixing the bugs I found while trying to run
Ocarina on a Raspberry Pi 2.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This greatly improves usability while searching, since we no longer have
to refilter the song list for every key press.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
A long int is shorter on ARM than x86, which could cause position and
duration values to get truncated. Additionally, quering gstreamer with
a long int causes a compile error on ARM. Let's just do the right thing
and make this value an int64_t.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
The main focus of this release was removing the clunky callback system
and replacing it with a way to notify queues directly that tracks have
been changed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Using this notification was causing segmentation faults when Ocarina was
closed with at least one temporary queue. I can handle everything I
need directly in the GUI without problems, so this notification really
isn't necessary.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It was useful for the 6.3 development cycle, but I haven't been keeping
this updated for each micro-release.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This class will be used to push queue changes directly to the GUI.
Currently changes get mapped through the old callbacks system, which can
lead to several inefficiencies because the GUI has to look up each queue
structure in a list.
This patch implements a basic QNotifier class and provides a function
for setting a Queue's notifier.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This lets the treeview completely display all the playlists, rather than
cutting off the last few characters.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Add gui controls for our new dynamic playlists:
- Unplayed Tracks,
- Most Played Tracks, and
- Least Played Tracks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Unplayed tracks is a dynamic playlist generated whenever we are asked to
select the "Unplayed" playlist. Note that dynamic playlists aren't
hooked up to the other playlist functions (has, add, del, or
get_tracks). This is to avoid adding them to the index and potentially
writing out to disk.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This will go unnoticed for Favorites and Banned playlists, but will
allow dynamic playlists to be refreshed without switching to a different
playlist first.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Once the check box was enabled, we were never setting the count again.
This means that changing pause count from 1 to 2 did not change the
count in the backend.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I can use the lowercase text from string :: lowercase() and take a
single pass over a single string (rather than iterating through a list
of strings).
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function converts unsigned ints into strings. This allows me to
replace several almost identical functions with one function call.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The lib/ experiment made the gui code a little more complicated than I
was expecting, so I'm going to begin merging everything back into gui/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I don't include unit tests in the tarball for releases, so I need to
check for this directory when telling Scons what to build.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Just calling audio :: next() will advance to the next song, but won't
change if we're playing music or not. I think this is what we want to
do when banning tracks.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This file doesn't do anything anymore, so move the init functions into
main.cpp and remove the file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
If .debug exists, then we'll compile as a debug build. This will let me
toggle debug status during development without needing to worry about
committing the change.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Other files in the gui implement their classes directly, rather than
making extra functions. Let's do that here, too.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
These buttons directly affect audio playback, so let's move them with
the rest of the audio buttons.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I move the code into a new cpp file, so it is no longer a header-only
library. I also take the chance to add a for-each function for testing
iterators.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I think it makes sense to handle this directly from the driver, rather
than going through a callback.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I can handle these widgets directly from within the gst driver. I think
this is easier (and more straightforward) than handling this in a
separate file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This means I no longer need to pass argc and argv parameters to core/,
so I can eventually work towards removing the Driver :: init() function.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This was used to get around layering issues with the gstreamer driver.
Now that the gstreamer implementation is in the gui code we can have it
call audio::next() directly.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It's not used anywhere else except during this one test, so move it out
of the global include files.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The driver is intended to be a small class, so put it in the audio code
now and we'll clean it up in future patches.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is a straight copy-and-paste of the header file and the code
implementing it. I intent to clean this up with future patches.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch fixes up formatting a little bit and removes the Track
section of the DESIGN document.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This shifts the taglib code into library.cpp. I also remove the tagdb
section of the DESIGN document.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This has been disabled for some time. I added a test for adding track
indexes to the filter upon creation, but it doesn't properly test adding
to the filter when reading from disk.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This code is really testing date and locale handling, so this patch
renames the function to match what it actually does. While I'm at it, I
also introduce some cleanups.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This returns the actual size of the database, so be careful when using
it! The intent of this function is to allow some kind of iteration when
loading databases.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The track_db doesn't have autosaving enabled for performance reasons.
This lets us add several tracks to the database between saves, but it
also means we need to provide a commit() function.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm going to need to split this value earlier to do a unique lookup when
inserting, so the constructor can take the relative path to make things
easier.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I want to test basic reading and writing before running the functional
test, since the functional test will eventually trigger database
commits.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This makes the code a little bit cleaner, since we don't need to keep
doing lookups for each test run.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I don't want to expose the date structure outside of the track class, so
I'll provide a comparison function instead.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The new constructor covers these cases without needing to do taglib
stuff inside the Track class.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch creates a new structure to track the last played date, which
can be expanded into a class at some future point. Additionally, I use
strftime() to calculate the current date based on the user's current
locale settings.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I don't want anybody outside of this class changing the value, so it
shouldn't be public. I also change the primary key to use library index
instead of the full filepath while I'm at it.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I don't think this value needs to be stored anywhere in the Track class
since it's fairly easy to calculate. Let's convert it into a function
for now and reevaluate later!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I provide an accessor function to keep this value from ever getting
changed outside of the Track class.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
We want to make sure that the _library size is decremented whenever a
track is removed or destroyed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I want to provide the Library, Artist, Album, and Genre tags to the
Track on construction to (hopefully) eliminate the Track::tag()
function.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I also use this opportunity to create a new default constructor test for
the Track tag. This patch also disables the tags test since the tagdb
will be going away soon.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I was only ever comparing the lowercase version of the name, so this
should be done in a single place (the GenericTag) to make maintenance
easier.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch moves the library_db into tags/library.cpp, where it can be
effectively managed by the Library tag. For this to work, I need to add
some extra functions to the tags namespace to:
- Create new Library tags,
- Find tags by index,
- Remove the Library at a specific index, and
- Find the actual size of the library_db.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The genre_db should really be controlled from within the Genre tag,
so this patch adds functions to find or create Genre tags to the tags
namespace.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The album_db should really be controlled from within the Album tag, so
this patch adds functions to find or create Album tags to the tags
namespace.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The artist_db should really be controlled from within the Artist tag, so
this patch creates a new tags namespace containing functions that will
find or create tags as they are requested.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This tests all the basic things that the tag does: storing values and
reading / writing from file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
- This tag now inherits from GenericTag.
- Add a Genre-specific unit test.
- Remove the genre tag section of the DESIGN file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Also make it inherit from the GenericTag base class. Also also, add a
unit test specific to Album tags. Finally, I remove the corresponding
section of the DESIGN file since it is no longer needed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
core/tags.cpp was WAY too big, so I moved this code into a new file in
its own directory. I also created a new unit test just for testing the
Artist tag.
This patch disables the "tags" test since it conflicts with the
tests/core/tags/ directory. This is okay because the tagdb is gradually
being phased out!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I created a new directory for tag related code. This keeps the core/
directory cleaner and prevents file name collisions between the library
layer and the library tag.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
- Fix a typo in where the gstreamer code is going to end up
- Change testing goal to reflect that I rewrote the sconscript instead
of creating a new bash script.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I don't want anybody outside of the IndexEntry class to modify the
values in this container. This patch makes it private and provides
iterator access instead.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This variable should only be set by the Database when a DatabaseItem is
first created. This means I should hide _index from the rest of the
world to prevent accidental modifications. I also add an accessor
function for other code that needs to read _index.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I transfer everything from my DESIGN file into doxygen, and then remove
the section from DESIGN.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I add more detailed documentation matching what was in my DESIGN file.
In addition, I also prefix private File members with an underscore like
I do in other Ocarina classes.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
My old testing system was rather convoluted. This patch makes the
Sconscript file easier to follow.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I added a little more detail about how this function works. This lets
me remove this section from the DESIGN file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Gtk::Main() is deprecated, and causes several warnings to show up when
closing Ocarina. I guess it's time to switch to Gtk::Application()!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Setting from argv[0] seemed like a good idea at the time, but argv[0]
can change based on how the user calls Ocarina (ocarina, ./ocarina,
/usr/bin/ocarina, ...). This patch changes back to using the reliable
/proc/self/exe method.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I want to have all of Ocarina documented in the code, rather than in a
difficult-to-maintain DESIGN file. Let's get going on that!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The collection manager is the only thing that uses the idle queue, so
let's keep all this code together.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This calls the audio :: play() function, rather than having the button
call into the audio layer directly. With this patch, the on_play()
callback is unused.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This issue was solved in Ocarina 6.1.3, but I didn't add a unit test for
it. This patch adds a test.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I wasn't doing this before, so banned songs were showing up in the
collection list again. I think this is kind of an ugly fix, though.
Perhaps there is a better way to do it?
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Ocarina was preserving the results set even if there were 0 search
results for the entire search string. So a search for "walllllll" would
still return results for "wall".
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The user could search for a term that isn't stored in the filter index.
This is represented through a NULL pointer returned from the
Index.find() function. Let's check this pointer before attempting to
dereference it ...
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Initialize everything from the core/ layer, that way lib/ doesn't need
to know the correct order.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Whenever a Track is destructed, library->count is decremented. This
means that even if tagging fails we need to increment library->count to
keep this value consistent.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Without this check we could end up creating a Track for a .ini file or
some other non-audio file.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
o_collection_* was easily confused with widgets on the collection tab,
so I renamed everything to be less confusing.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
- Adjust spacing of the FileChooser
- Rename button from OK -> Add
- Add tooltips to the buttons
- Rename column from Path -> Collection
- Filter out files that aren't directories
This will provide an interface for accessing widgets, and make it easier
to swap out different builder files.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I replace the /proc/self/exe method with a simple hard-coded string.
This means that binaries run from the source directory need to be run
from the root of the source directory.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This just checks that the deck was initialized. To really be complete,
it should really check that ALL core libraries are initialized.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
My hope is that putting lib/ between core/ and gui/ will help clean up
gui code, since everything will no longer be in a single place.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I move all of the core tests into the core/ directory to keep them
together. Gui unit tests will be put in new directories.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I now mimic the effects of the "changed" callback with inheritance.
This makes for a cleaner implementation.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I plan to introduce a new lib/ that sits between the gui and the backend
files (similar to how glibc sits between the kernel and userspace).
This gets the rename out of the way before I change my mind again.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Changes to the deck removed the on_pq_created() callback that we looked
for to create new tabs. This patch creates tabs correctly.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch reworks the unit test using the TestDriver audio driver. I
also recode the audio layer to match the design and drastically clean up
the code.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This can only be hit when the tagdb has no tracks in it, since you can't
add a NULL pointer to the recent queue.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch updates the design to something that makes a bit more sense,
and works with the new audio drivers.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This would have to happen eventually. Might as well do it now!
I also updated the TestDriver test to match the changes I had to make.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
The driver is used to select between gstreamer playback and a fake
playback mode used only when testing.
Currently the GSTDriver has empty functions. It will be implemented as
the audio.cpp file is updated.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
TempQueues create a way to trigger deck :: write() whenever a queue
changes. This means higher layers don't need to remember to save after
changes!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This patch actually breaks a bunch of things, but I just want to be done
with the deck changes for now. I'll go back and fix things before
releasing!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I update the unit test and redo much of the code to be cleaner and make
more sense. One big improvement is that the recently played queue will
now be managed by the deck.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Keeping separate directories for all of these files isn't the most
obvious way to do things. Instead, move everything into the same
directory.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I'm about to bump the version number for the deck layer, so it makes
senes that different files need different version numbers.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This fixes the gui, deck, and audio code due to the library changes I
just did.
NOTE: Library updating callbacks have been disabled in the gui.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Lots of changes here! I switched from using track and library ids to
passing pointers, renamed some functions, and made the code much
cleaner.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This function is called to increment play count and set "date last
played" variables. Moving this into the Track class lets me remove an
internal callback and a few other unnecessary functions.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I updated the code to better match how I use playlists and to make sure
that everything is tested.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I now have a single function rather than 4 individual functions. The
code is cleaner, and I've added it to the unit test.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Apparently it's not okay to return str.c_str() to caller functions,
because str will go out of scope...
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This is best implemented in a derived class, since it's only used by the
recently played queue.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
It should take a Track pointer, rather than a track_id. This makes the
code easier to work with.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
... and just into the tests/ directory. I also reworked the Sconscript
to compile everything using only the lib/ files that are needed.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This might have made more sense for an earlier version of the
DatabaseEntry class, but as far as I can tell this test only checks code
that exists inside this file. This means I can removed it without
reducing code coverage.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Looks like I missed updating a few places in the File class. I do that
now, and I also began updating the unit test to the new system.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Add in several new features like:
- Don't exit until the specific test function completes.
- Make it easier to run named tests from C++.
- Use a macro to find line number when calling test :: equal().
- Use a macro to do basic setup and cleanup between test functions.
Also update the version test while I'm at it.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I remove the "on_queue_changed" callback in the flag handler functions,
so changes won't trigger a save until I can update later layers.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This makes testing easier, since I'll only see the test I need and not
everything that runs before it.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
So far I have renamed variables, changed a few functions, and updated
all the code that was affected.
Oh, I also started a new unit test.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
Queues are read from disk *before* libraries are read, meaning we can't
calculate the length right away. But if we don't calculate the length,
then the first time a track is removed from a queue the length will be
set to (0 - track_length). This is wrong.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
I only needed this to make the jump from Ocarina 5.10 -> Ocarina 6.0.
It's not needed anymore, now that 6.0 is out.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
This should offer a performance increase since the item to insert will
only be copied if it is not already in the database.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
Inserting into a vector can sometimes cause the entire vector to
reallocate itself. The insert() function returns a pointer to the
caller, so this reallocation could invalidate the returned pointer.
This is not what we want.
Instead, store pointers to the data in the vector. C++ provides a
default copy constructor that can be used to allocate a new item before
inserting. By doing it this way callers won't have to allocate memory
themselves. In addition, I will no longer need to keep a valid bit
since we can simply check for a NULL entry in the database.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
This gives me the item directly, which is usually what I want when I
call these functions. Save iterators for iterating.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
I properly initialize variables, and I created supporting databases that
will be used to look up artist, album, genre and library information.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
This layer will be separate from the library updating code. This will
give me a place to manage the various databases without extra code to
scan and update paths.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
Rather than returning an index into the database, instead return an
iterator pointing at the item we just inserted.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
This gives me a chance to write out more information about each class,
so I'll have an easier time knowing what is going on if I ever need to
revisit the design.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I only had config so I could easily refer to the original Sconstruct. I
don't need that anymore =)
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
Calculating through the iterator may lead to unexpected problems. We
already know the id of every database entry, so we might as well use it
directly.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
If a title began with a number then the number would be read as part of
the length, adding extra time. So a track with length "100" and title
"42 abcde" would be read back as having length "10042" and title "abcde"
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
When items are deleted from a database we write out a line representing
"invalid entry". This patch changes the invalid entry line from "0 " to
"0"
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
- Double check that track->valid == true before notifying the UI that
there is a new track.
- Use primary_key() instead of manually calculating the full filepath.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
I found that databases were always decrementing _size when remove() was
called. This patch fixes the bug by checking if the entry is valid
before removal.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
Recalculating this doesn't change the runtime significantly, so we might
as well save some disk space.
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
This will let me set up a Track class that has pointers to the
corresponding artist, album and genre information without needing to
know their IDs directly. Having this information available means I
won't need to keep a "join struct" when doing lookups - instead I can
return a pointer to a Track class that already knows everything.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I didn't have any changes to make to the IdleQueue itself, but I did
need to update the unit test and reword a few things in the design.
Signed-off-by: Anna Schuamker <schumaker.anna@gmail.com>
- filter :: add() now returns the lowercased text
- Don't cache lowercased strings
- Remove functions depending on CONFIG_TEST
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The SimPL was essentially a reworded GPL v2 license, so we might as well
have the original GPL v2 text.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I updated the design and rewrote the unit tests. This creates something
more consistent with how I ended up using the index.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I add:
- Autosaving option
- Real iterators
- Better accessor functions
The new design and unit test also allows me to remove the 300,000+ line
"database.good" file that the old tests were based on.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Needing to use throw / catch was getting in the way. Instead, check for
a boolean return value.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I changed primary_key() into a function since it is only called once,
and there is no point in using more mmemory than I need to. I also
created a basic unit test for everything that database entries are
supposed to do.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I was double clicking tracks in the gui, and they were removed from the
playqueue! This patch fixes that.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This time I don't keep a global "sorting count". Instead, this count
belongs to individual tabs so flipping between them quickly could
display different sorting fields.
Signed-off-by: Anna Schumaker <schuamker.anna@gmail.com>
Keeping these documents updated with the top-level design.txt was
annoying. Moving forward, I would like to keep a single document up to
date without extra hassle.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I am going to delete the design/ directory and just keep a single file
instead. I don't want to lose my ideas!
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I'm taking a break from gui code to clean up the build system and update
my unit tests. This patch updates how code is built, and reworks my
"print" test to test version number instead.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This helps to clean out tab.cpp so I can keep track of what still needs
to be done. I also adjusted some of the spacing and section divisions.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This appears to happen automatically, but appearances can be deceiving.
Remove pages anywa just to be safe.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I've been putting this off for a while since it seemed like a lot of
work. Time to get it done!
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This one is based on inheritance, and I think it will be the best way to
create several tab types that do things just slightly differently.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I need to create a FilterDesc struct with needed widgets and then
filtering can happen generically on all tabs!
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I'm creating as many "static tabs" as I can using GtkBuilder, and
splitting their code out of tabs.cpp. This should help to contain the
growth of this file and make all the code easier to work with.
This patch begins the redesign and adds beginning code for a new
collection tab.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I made a couple of templated functions to get widgets and objects out of
the Gtk::Builder easier.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Number keys to switch pages
- c, h, p, m to switch to collection, history, playlist and collection
manager tabs.
- Slash key to focus on the search entry
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I need this in case the user deletes all tracks from a playqueue without
adding anything by the time next() is called.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I'm honestly not sure why this is needed, but using ref pointers
prevents several lines of warning messages.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This is called by the GUI to tell the playqueue that a track has been
selected. This gives the PQ a chance to (possibly) remove it.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I wasn't initializing the variable, so it was sometimes drawing buttons
next to the filter entry bar.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I love tis feature, and I've been missing it the last few days of
Ocarina 6.0 preview testing.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Initialize stamp with a random integer (this is how a Gtk::ListStore
works)
- Increment the stamp in a way that it will never be 0 (AKA: invalid)
- iter_n_root_children() does not take any arguments, so fix up my
function.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Create various helper functions to call during construction
Create multiple tab label classes to use for each type of tab.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
When a track finishes, I tell the library to update playcount. Then,
the library triggers a callback to the playqueue deck telling it to
update.
This patch also finds and prints the track that causes a gstreamer
error.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Reimplement binary search for neater code
- Flip sort order when resetting sort if the first field is the one we
are sorting by.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The history playqueue should never change sort order, so use this flag
to prevent user changes.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I set up a 3-second timeout to decrement the count. When the count is
at 0, I reset sorting on the playlist.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
My test was done with a library size of 8040.
Before this patch, I make 21919628 calls to my "less_than" function.
With this patch, I now make 101205 calls to my "less than" function.
This comes out to a 216-X improvement. I should have done this sooner.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I don't have user-configurable sorting (yet), but for now I'm sorting by
Artist -> Year -> Track #.
I also fix a bug where the library wasn't lowercasing artist, album,
genere, and track fields when reading from file.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Start on the collection page. I eventually want to display the first
enable playqueue, though.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The history and collection playqueues are never saved to disk, so I only
care about saving when a flag is changed.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Now we are passed the page on the switch_page() signal. This saves time
iterating and comparing.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
When the count is changed or pausing finishes, I trigger this callback
to notify the UI. I also added in a line to enable pausing any time the
count is incremented.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I display the runtime of the currently visible playqueue in the bottom
right of the screen. When the collection manager is visible, I hide
this label.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I almost did this on the gui side, but then I remembered that this isn't
a trivial job. I chose to stick with my rule: "if something can be done
in the backend then it should be done in the backend"
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Now it says "Collection" to match "Collection Manager" it was either
this or have a "Library" tab and a "Library Manager"
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Check for path existing in the library already before adding again.
- Iterate over track database using <= for comparison, and not just <
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Only available when CONFIG_TESTING is enabled. Used to test clearing
the library and library playqueue for testing.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This prevents an error message (and possible corruption) by continuing
with the open() function even if the file doesn't exist.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This was a bug I discovered when double clicking on paths in the
collection manager to change the path in the FileChooserWidget.
Before this patch, strings could be read as:
<string> /home/anna/Music</string>
Now, the same string will be read as:
<string>/home/anna/Music</string>
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
For some reason I was only loading the library_db, and ignoring the
others. I fix this, and send out callbacks for each track loaded.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I implemented an entire Gtk::TreeModel in this commit, plus some minor
supporting code in the library to look up playlist entries by index.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The signal connections for these features are really difficult to test
programmatically, but I can test the effects by calling each function
directly.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I had these hidden so the users really, really know that they are
supposed to select directories. Now I've made it easier to browse the
filesystem through the Collection Manager, so hiding files doesn't make
sense.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This allows a user to explore what has been added in each of their
library paths. Right now I filter for directories only, but it may be a
good idea to change this in the future.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I add a little bit of spacing between widgets so they're not so crowded
together. I also adjust things away from the edges of the window
because I tihnk it looks better this way.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This adds support for callbacks telling us when a new library path is
added and when a path has been updated.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Gstreamer includes <errno.h>, which already defines several of these
symbols. I rename them to avoid namespace collisions. Perhaps a better
solution would be to use the errno.h definitions directly?
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This is used for the recently played playqueue to iterate backwards when
the previous() function is called.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I was using CONFIG_DEBUG for these, but they really should be under
CONFIG_TEST for use by the testing code ONLY.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This returns a pointer to the library :: Library structure requested.
The gui will use this to display information about each path.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I track the size of each library path for display purposes. I also had
to add in a check for if a new track already exists in the db before
tagging it so updating a library should be much faster now.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The legacy file type will only be used for importing old libraries, so
point things to this directory on construction.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Combine Artist and Genre struct
- Add in exceptions, rather than boolean returns
- Update the library through idle tasks
I have not implemented importing Ocarina 5.11 libraries yet.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I do not make any of the library spec changes yet, instead I update the
backend code so it compiles and still works with the changes I have made
so far.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I added in an update_all() button and combined two identical database
structures. Hopefully this will help to clean up the code.
I also added in wording for how to use the idle queue to scan paths.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I changed the two playlists that are supported, added in exception
handling, and removed the list() function since I will always know the
names of playlists. I also rename everything to "playlist" from
"group".
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This function will convert the provided text to lowercase. This really
isn't a filter function, but the filter already implements a lowercase
cache that should be useful.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I had been returning success / failed boolean values for various
operations. I think it's better to throw an exception in these
"exceptional" circumstances since error values can give more information
about why a function failed.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Playlist -> playqueue. Playqueue sounds more temporary, which better
represents how I intend this code to be used.
- Groups -> playlist. A playlist is the accepted term for what I am
trying to create here.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This patch writes out various modifications the GUI will require the
back-end library to make. This includes:
- Rename playlists to playqueues and groups to playlists.
- Make library information accessable.
- Use try/catch style errors instead of returning bool in a few places.
- Extra playqueue accessablity functions.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This matches the current state of the backend library and does not have
any tweaks for the GUI.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I've taken a first pass at the Ocarina 6.0 GUI. The backend will need
some tweaking before this design can be used.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
My new implementation puts everything under lib/ instead of treating the
backend library as a different project.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This patch implements the pause-after-N-tracks feature. I also included
various improvements to the audio code.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Seek(), position() and duration() functions are implemented
- There are bugs in the test program :(
- Clean up next()
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The read and write functions will be called by a higher up layer, so I
need to open the file manually in the test.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I make sure to remove empty playlists from the deck and throw an error
if there are no playable tracks on the deck.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The file will be passed in by the deck layer, since it stores multiple
files. I just fake up a file in test_2() that is used for storing the
playlist.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
To keep the design readable, I split the playlist class (playlist.txt)
from the playlist deck (deck.txt).
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I recreate the directory deleted in test 6c and make sure everything is
added back to the database in new rows.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I was using _size as an index into the database, but _size represents
the total number of valid rows and not the id of the new item. If a row
is deleted _size will decrease and the wrong entries will be marked
valid.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I scan the track database and remove files that no longer exist. I
don't yet add in new tracks found in the directories.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This patch updates the design so indexes are built upon databases using
a special IndexEntry. I also updated the tests/index/ test to match
the new system, but I have not updated filter or group tests yet.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I require entries to have a "primary key" that is stored in a map to
make it easy to find database rows by key.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I made a few modifications to the database, and introduced an
"IndexEntry" database type to do the exact same thing :)
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Add more to the Library, Playlist and Audio design to match how I expect
the GUI to use the backend.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
If the id is valid, I fill out a song structure and return true.
If the id is invalid, I return false.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This is each song's track number, play count, and anything else specific
to a single file. After updating, save all the changed databases.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Passing the TagLib :: Tag pointer is much easier and cuts down on extra
arguments to each constructor.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I don't build up a complete set of databases yet, but I do create the
Artist name database to use later.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Eventually these functions may have to become idle tasks, but for now I
write to disk whenever the library_db is changed and then read from disk
by calling the init() function.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I can add and remove root-level directories from the library database.
I do not save the database when modified, and I don't yet run an update
on all the files.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Check if we are finding the "last" iterator in an empty database
- Better print() descriptions
- Print test return codes that aren't 0 to help find segfaults
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
It doesn't make sense to need to set this value outside of the database
code like I had been doing. So when a new row is inserted mark it as
valid right away.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This function is used in debug mode to print the current status of the
index. I also created a print_keys() function to only list the keys.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Other tests may need to print out a database. To make this easier I've
added a print() function to the base database class. This function will
only exist when CONFIG.TEST == True, so don't use it outside of testing!
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Rather than doing everything in tedious if blocks written in any order,
I instead resolve dependencies using a much simpler loop. At the moment
each module only depends on a single other module, so this will have to
be extended if I ever need multiple-dependency resolution.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Rather than setting up all variables twice, just call reset() to
initialize everything. *BONUS* Reset can be used to initialize the
value of CONFIG.TEST!
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I was using my own cpp file to remove old test data to start with a
clean slate. I've decided it's easier to just remove the files before
running tests if they exist.
I also use this patch to update the test design and add an idea for the
future.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
For some reason I turned the file test into three separate files. All
other tests were in a single source file, so I updated file tests to
match.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
"basic" doesn't really fit the description for what I'm testing here. I
was expecting to do a series of unrelated tests, but all I'm really
doing it testing the print function.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The library will need databases that have unique values (such as the
artist or album tables). This patch adds support for that in my
existing database code.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I assign tags to the 1, 10, 60, and 600 second long ogg files as they
are copied to the new library directory. This is much faster than
generating sound files on the fly, but it makes this commit 2.5MB in
size...
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
The idle queue is used to schedule tasks ... later. This code was
mostly adoted from a reference TDD experiment by Josh Larson
(themutatedshrimp@gmail.com). Thanks Josh!
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I only handle the "All Music", "Library" and "Banned" groups at the
moment but I'll eventually add in more features (in future versions).
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I still have some back-end work to do first, but I should start thinking
out what users will see.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I have everything except for save() and load() written. My unittest is
fairly comprehensive and tests everything implemented so far, so with
any luck putting in save() and load() features will go quickly.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Save recent database changes
- Move the idle queue after the database
- Put file class definition notation
- Update the todo list
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I had planned on using the stream operator for my database class but
this created some crazy compiler error that I was having difficulty
figuring out. I decided to take the easy route for now and instead
create read() and write() functions that do exactly the same thing.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
Items will be marked "invalid" rather than directly removed from the
database. This make it easier, since I won't need to reassign IDs to
every database item after the removed one.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
A database may have invalid rows. If this is the case, then the next()
function needs to return the id of the next valid row. I'm aware that
this could get horribly inefficient on large DBs with many invalid rows.
I don't expect people to delete large chunks of music all at once, but a
defragment tool is on my "todo" list for a future Ocarina version.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I've been excited about this! I think it'll be a better design than
what I had for Ocarina 5.x.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I need a way to return the progress of the idle queue and to indicate
when it is out of tasks so idle threads can stop running.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
I changed print to compile in the dprint() function when the testing
flag is enabled. This allows tests to have the same output regardless
of debugging status.
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
- Don't be verbose when removing files.
- Reverse diff order so output makes more sense.
- Only strip whitespace from the end of lines.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Inherit from fstream to gain access to << and >> operators.
- Make the file version accessable to the outside world.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Support OPEN_READ and OPEN_WRITE
- Update the design to accomidate for error checking
- Add lib/test.cpp containing basic functions that can be used for
testing
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The class resolves the path to the ocarina directory based on the file
hint provided. NOTE: compile-debug.good and compile.good resolve paths
to my home directory. Other users will need to change the values for
the test to pass.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm starting to implement file access. I've reread the design and
updated a few things to make it easier to test.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This will give some better stability to the design document, since
entries won't shift around based on python memory locations.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The class is in charge of resetting fields at will, and will be able to
maintain everything easier than if I were to do it by hand.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I was using a debug and a release environment for programs, that way
both versions of tests could be checked. Instead, it'll be simpler to
only use a single environment and then control debug information using
CONFIG_DEBUG.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Each component has its own text file. I merge everything together with
simple dependency resolution so I can figure out implementation order
easier.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I store release and debug options in a list so that env.Replace() can be
used to set, modify, and restore values.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This class will manage save files so paths don't need to be resolved in
multiple places. I'll also use it for reading and writing with version
information.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I decided to put the library into a namespace to keep the code clean. I
also added an update algorithm and made minor naming changes.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I renamed "tags" to "groups" to avoid confusion with ID3 tags. I also
thought out a better plan for eventually implementing user defined tags
so that I can build up to them with testing along the way. With any
luck, I won't overwhelm myself with features =).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Up until now I've just been coding whatever I feel like without thinking
about it too much. This time I'm actually going to come up with an
ocarina design and then implement it according to the document. The doc
can then act as a reference for how and why things are done for future
work.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Right now it's just a toplevel window. I also added a script for
launching the new gui without needing to manually set the environment
variable.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I only have one application so there is no point in having a way to
create multiple application directories.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The plan is to port everything to gtkmm since using the C functions is
beginning to get annoying. Compile the new code using `scons newgui`
for now.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
It's a 2 line function that was used in only one place. Time to remove
it and simplify the surrounding code.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I was keeping a vector of objects, and then pass pointers to these
objects around everywhere. HOWEVER, when vectors are resized they
allocate new memory and copy things over invalidating iterators and
pointers to the original objects. This can cause memory corruption
issues when I try to use a pointer to an object that no longer exists.
The simple solution? Allocate tracks dynamically and then store the
pointer in the library path.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I want to remove the various idle task types that have built up and
replace everything with a single idle type. I also want the idle layer
to be the only place new tasks are allocated.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Now that I'm using vectors for everything I don't need to maintain my
own class. Nothing uses it now, so it can be safely removed.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
For each library path, I replace the linked list with a vector allowing
me to easily index into the list to find tracks.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This corrects the package build to look for a tarbal named
"ocarina-5.11.1.tar.gz" instead of "ocarina-5.11.tar.gz"
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Otherwise songs might error out part way through playing and skip to
something else. It doesn't make sense and I wish I knew why :(
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The vector should be simpler than a linked list for tracking playlists.
I also changed reading playlists to use a function in the playlist class
rather than a function outside of the playlist.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to gradually move this out of the playlist/ directory since it
doesn't really belong there. I also plan on cleaning up / rewriting
much of the code as I go along.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I plan on removing this class in favor STL classes. I probably
shouldn't have even tried to implement this myself...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Most of this was commented out and hasn't been used in almost a year.
The new gstreamer code doesn't have the property probe feature anymore,
so I can't reimplement my old alsa code. I'll drop it for now and
figure it out later (after cleaning up this other code).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
When scrolling I think it's important to show a few rows that are coming
up next so users know they can stop scrolling and not need to reverse.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Gstreamer 1.0 has been out for a while and replaces gstreamer 0.10.
Let's make sure we use the most recent version going forward.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I used to use my own inverted index implementation, which makes sense if
I'm searching all songs for a specific match. Instead, GTK was visiting
each track and asking "does this song match?" and this requires a
different implementation. So rather than make an index, instead I have
each track generate substrings for its tags and then I compare filter
text against the substring set.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I also replace a few PLAYLIST_* notifications with a generic
PLAYLIST_CHANGED notification for when small changes occur. I think
that using set_flag() and check_flag() will make code cleaner and easier
to maintain.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't want to keep one function in a file by itself. Instead, let's
just move it into the main playlist file.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
My "insert while sorted" code was getting complicated, and didn't send
all the notifications to the UI (only the first ~1200 songs were
displayed). This patch both simplifies the code and produces the right
answer without a noticable performance penalty.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I can make this simplier by simply passing the index into the vector,
rather than needing to calculate the iterator and pass the index.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
There is no reason to track this on my own, iterating over all tracks
and calculating it on the fly is easier and basically unnoticable.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't need to iterate through a linked list to find the track anymore.
Instead, I can access tracks directly using an index.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I know what playlists are library, recent and banned. All others are
just named "Playlist" so there is no need to set up a name variable.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Vectors are more straightforward than linked lists and they should allow
me to clean up the code a lot. For now I just put in the straight
conversion, I'll clean things up in future patches.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I didn't realize this was still around. It should be removed since I
switched to a notification system instead of using the renderer.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This finishes the job I started in the last commit. Once again, I use
an enum of string properties to determine the right field to return.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Rathen than using a bunch of get_PROPERTY_NAME() functions, I think it's
cleaner to use dictionary-like indexing to access properties. This
patch converts most track access functions, but I haven't gotten around
to strings yet.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I also respond to the PLAYLIST_SORTED notification so we do the right
thing when loading a playlist during startup. I don't put the sort
button on the library, recent list or banned list because I don't think
these lists should ever be sorted.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I reused my old dice png from several releases ago. This implements the
"switch a playlist from set to queue and back again" feature that I
wanted.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Rather than hardcode this as a flag, if I set this through the
preferences code users can change the value.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Flags let me manually set properties after the playlist has been
created, rather than needing to decide upfront with no way of converting
to something else.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I plan on removing the extra playlist classes to simplify code a bit, so
this function needs to be implemented for everything.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I created simpler functions using the push_front() / push_back() names
that stl uses. If we're a set-type playlist, then call the
insert_sorted function instead. I also remove unnecessary bulk-inserts
of a single track. Packing and unpacking a list each time seems stupid.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Basically, don't list duplicates. If a song on the list is added again,
instead I move it to the top of the list.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Read a command from the pipe, rather than reading a file with a
command in it.
- Use a single ocarina script for all commands, rather than several two
line scripts.
- Change ocarina.bin to point to ocarina instead of ocarina-player for
convenience.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The build system hadn't been touched in a while, so it needed some
cleaning up. I moved ocarina-specific files into the ocarina/ directory
and use the ocarina/Sconscript to set up build commands.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
THese are screenshots from 2010 and the early Ocarina 4.x days, so
they're somewhat out of date... I also remove a crude ocarina icon that
I'm surprised is still around.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This was old code that had been replaced by fs.cpp months ago. I must
have forgotten about removing the rest of it...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Ocarina no longer has a header file subdirectory so there is no reason
to have a libsaria subdirectory anymore. Putting header files directly
in the include/ directory is a bit simpler.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The preference may be set to zero by the user but default to a non-zero
value. This can cause frustration on both the user and developer ends.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I was trying to add an empty list, rather than track items. This caused
the library count to increase (on the library path tab), but the library
playlist was never given track pointers so you had to restart ocarina to
see songs.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I eventually want to use a unix socket so I can get bidirectional
access. For now, I'll just reuse the old code.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I have notifications to handle everything the renderer used to do, and
I've removed it from the UI side.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
current_widgets() works based on the current tab number, and the
"switch-page" signal is triggered BEFORE the current page is updated in
the GtkNotebook structure. This means that I was actually setting the
length based on the previous tab, and not the new one.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
ocarina/playlist/ was the last subdirectory remaining in the ocarina
code, and I can finally remove it. Thank you GtkBuilder! At this
point, there is only one ocarina header file, so I move it to the main
ocarina directory.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
If the current playlist is the library or banned list, I toggle the
banned state. Otherwise, I remove them from the current playlist.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This lets me remove the "if treeview is focused" special cases that keep
popping up in the window keypress handler.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I already use "Return" for focusing the treeview from the main window or
from the filter entry. If the treeview is already focused, I have it
begin playing whatever song is under the cursor.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Disabled playlists are ignored when picking the next song. I grey-out
the widgets on the UI when this notification is received. I keep
filtering enabled this time (the entry was disabled too in Ocarina 5.9)
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I put it on the tab page this time, instead of in the tab label. I
don't want wide tab labels, so I should eventually come up with a way of
closing playlists without having to change tabs. Maybe a right-click
menu?
I also noticed that the libsaria delete_playlist() code didn't work, so
I simplified it a bit.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
It's easier to refilter automatically after setting the filter text,
rather than going through a bunch of function pointers to change the filter.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
It was commented out and unused. I also commented out the "Unhandled
key: " message to keep from filling up terminal screens when treeviews
respond to a keypress.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The first time Escape is pressed, rows are unselected. The second time
Escape is pressed, the toplevel window is selected.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Instead of using a "on_new_playlist()" function, I now use the
notification system to tell the gui that a new playlist has been
created. For now I just put it on the front of the tab list.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Dynamic playlists are going to need to run the same code to generate
playlist tabs as the static tabs. Since I don't know how to use
GtkBuilder fragments, instead I write the code for generating each page.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
One for managing the notebook tabs (tabs.cpp) and one for managing a
specific playlist page (playlist.cpp).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Most of this was already commented out, but I also took the time to
figure out what header files are no longer needed.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'll know if a shortcut key is pressed, so I only want to print out
unhandled keys so I know their names.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Since I don't have dynamic playlists re-implemented yet, I just swtch
between the library, recent, and banned playlists.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I use this to find the set of widgets associated with the current
playlist page. This also makes current_playlist() easy, since I can
just return the playlist from the widgets struct. I also moved these
functions to the top of the file so the filter entries can eventually
set focus when "slash" is pressed.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I have to track if a filter-text entry has focus to do this properly,
otherwise using a shortcut key while searching a playlist will trigger
that shortcut.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm only using this function for updating the progress bar now, so it
doesn't need a faster response time. I can drop CPU usage a little bit
by adding a longer delay between updates, without really noticing the
difference.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This was in body/playlist.cpp, but I eventually plan on removing this
file so the code I'm using from there needs to be moved somewhere else.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This notification is sent when a track in the playlist is updated, such
as when the play count is incremented. I also remove the
track_updated() functions from the library renderer and ocarina::Playlist.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This class is slowly going away, and these functions have already been
reimplemented using my GtkBuilder interface.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Dynamic playlists are disabled right now, so I'm making use of this time
to clear out old code. This patch removes library renderer functions
that have already been reimplemented.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
My old code was doing this by looking for widgets getting mapped or
unmapped. This was stupid, so now I'm using the GtkNotebook switch-page
signal.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Instead, I implement a new struct for grouping together the important
widgets of a playlist tab. I should be able to re-use this structure
for dynamic playlists.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't have a way to ban songs using GtkBuilder yet... that's coming,
but for now I'll just assume it works :)
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I've re-implemented everything using GtkBuilder, so now I don't need the
ocarina::Playlist for the library.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Used to notify the UI that the playlist size has changed. Other options
include: Set the size automatically when responding to PLAYLIST_ADD (and
evenutally "PLAYLIST_RM")
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This tab is appended at the end of the notebook, so it looks as if there
are two Library tabs. I'm going to use notifications and GtkBuilder on
the new tab to remove the PlaylistRenderer and to hopefully make adding
new features easier. Right now only inserting tracks into the
LibraryPlist works, and I eventually want to remove the LibraryPlist
liststore in favor of a custom treemodel.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I initially made this class so that multiple front ends could be used at
once and all receive the same notifications. I see now that this was a
stupid idea, since I only need to keep one list of the library. My
notify() function does the same stuff without the need for a driver
list.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Any void * will do, or even NULL! Try to keep notify.h up-to-date with
what argument is passed and please don't send out the same notification
with multiple argument types.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Right now it only notifies that an event happened. I think I should
eventually pass in an additional argument related to the event that
happened. This will allow me to send out notifications for preferences
or library paths changing.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The library treeview uses a cell renderer that needs the "toggled"
signal. Since this isn't a widget, I've been seeing a gtk warning when
I get_widget() tries to use the GTK_WIDGET() macro on it.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I moved it to the GtkNotebook action-area for the playlist tabs since I
ran out of room in the "Now Playing" section. I made the widgets
accessable through my get_widget() function, but it would be nice to
figure out how to add them in GtkBuilder.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I use this to select songs anywhere in the filesystem, not necessarily
in the library. I also renamed LibraryPathChooser to DirectoryChooser.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
There is some other problem with updating the renderer, but I'm more
concerned with working on the gui and moving on to other stuff. I'll
fix it later...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Clicking them doesn't do anything yet, and the buttons are
non-functional as well. But paths are displayed as they're configured!
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I modified the code slightly from what I used to have. The biggest
difference is changing the counter will always enable automatic pausing,
so I no longer need the extra click to enable this feature.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I check the size of the idle queue during the timeout poll and then
enable the progress bar. When the queue size reaches zero I hide the
bar again.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
And also
- Show / hide the play and pause buttons
- Remove the scrollbar from the now playing display
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Only the duration label changes, I don't do anything with the others
yet. I'll work on it later (once I get the rest of the UI converted
over).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The shortcuts were hiding more than they probably should have, and I
didn't have much using them. The only function in window.h that I'm
going to use is init_window(), so I'll just declare it in ocarina.h.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I wasn't doing anything with these, so they're just getting in the way
and increasing complexity. This change also allows me to remove the
"enabled" variable from the idle queue.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I feel that hand-written UI code is slowing me down, so I'm going to
switch to using glade / GtkBuilder to manage the UI as much as possible.
So far, I create, show, and destroy a window.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This makes more sense than pushing a single track into a list and then
iterating over the single item...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I was using multiple boolean fields, but I think it'll be easier to set
up a single bit-flag field instead.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I kept around the old list while I was converting everything over to the
new list. Now that I support all the needed features, I can remove the
old variable.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- The erase() function returns the previous item
- Implement a push_front() function
- Implement a pop_front() function
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Not really C++ iterators, but close enough. I can get the first and
last values values to use in for loops, I also made a next() function
for list items.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I need to check if the file is already in the library. I also made a
note for how this check could be done faster using a tree.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This function takes a function pointer argument that should return
"true" if the current item is the item we're looking for and "false"
otherwise.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Return the "count" variable and hope we don't have more than
MAX_UNSIGNED_INT objects in the list...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I free the memory in the destructor, too! Be careful, though, the copy
constructor isn't actually a copy constructor.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to gradually replace the stl list with my own implementation.
This should make everything more efficient and I won't have to deal with
those pesky iterators.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
It'll try to run a command passed through the shell, if the command
can't be found it'll run %APP-player.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Simpler package function and use $MAKEFLAGS. There is no longer a need
for DESTDIR or POSTFIX in the Sconstruct file anymore, either.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Otherwise it'll build just the ocarina subdirectory, which isn't useful
if I ever have multiple projects using libsaria.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I copy images and other files to lib/ocarina/ during the build to make
installing easier. The lib directory should always be relative to the
bin (executable) path, so I can easily find the lib path based on
executable path (/proc/self/exe).
I can also use this to find bugs in the buld process, such as adding a
file to the images/ directory but forgetting to add it as an install
target.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The app_directory() function sets the config.application variable, then
calls the Sconscript file in that directory.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This lets me pull code out of the generic Sconstruct, so it can't be
bad! I also removed the test directory since I never made unit tests.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Having tracks add themselves to the recent playlist means that it also
adds itself when going backwards through the playlist, resetting the
cur iterator and causing the same 2 songs to be played. To get around
this, I gave tracks a new load_unlisted() function to load without
adding themselves to the recently played list.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I created a new renderer function for updating tracks when they change.
Using this, I can show the new playcount of tracks as it is incremented.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Banning: Use the delete key on selected tracks from the library tab.
Unbanning: Use the delete key on selected tracks from the banned tab.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This allows me to restore it when restarting ocarina. I also need to
notify the renderer that the playlist status has changed so I can change
the button state.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Instead, I want to show them when they have tracks added to them. This
keeps the banned tab from being shown and then hidden right away during
startup.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Use g_signal_connect() when creating toggle buttons
- Only set the banned state on a track if it has changed
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
If the playlist size == 0, then we don't need to show it. This hides
the banned list when it doesn't contain any songs.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Right now, this just toggles the "banned" field in the Track class and
then skips to the next track.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I plan on using this to track if the user has banned a track or not.
This patch introduces the new field and handles the library version
upgrade.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Scripts should write commands to a temporary file and then write the
path to that file to the application pipe. I can then write results of
the command to this file before exiting.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to use the pipe with shell scripts for remote-controlling
ocarina (possibly through a web interface).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Passing individual variables through works for a small number of
variables, but passing a struct makes it easier to add new arguments.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
When we mark a song as played we should also mark that it was last
played today. With this, I think I'm finally using all my library path
fields!
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
On the libsaria side, I created a function for finding and deleting a
playlist pointer. On the ocarina side, I added a button to each
playlist tab to remove the tab.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Used for passing extra data through the button clicked callback. I also
use this patch to remove the extra GdkEvent argument passed to buttons,
since this argument isn't actually part of the callback...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I do this after choosing the next song and after tracks are removed from
each playlist. This allows me to remove playlists as they empty.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Before I was only adding tracks that were picked through the
deck::next() function. Now I have the track add itself to the recent
list (except when I'm playing an outside track).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This should set the gst pipeline to the correct state when the song is
loaded, rather than pausing after telling it to play.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Derived classes need to implement a do_add_tracks() function instead so
I have a single place to notify the renderer and save the playlist.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- The old header functions
- The old callback header file
- The old shortcut registering system
- The old main() code
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I've been wanting to do this for a long time. I don't think I need it
anymore, so it can all be safely removed.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Limiting rand to plist.size() * (3 / 4) kept causing songs at the end of
the range to get selected. This caused a backwards-scrolling effect as
songs were played. Instead, I want to pick from the next half of the
list to create a forward-scrolling effect.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The "S" or "Q" shortcut will create a new playlist on the front of the
deck, "s" or "q" creates a shortcut on the back of the deck.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't want to keep creating functions for doing things to playlists.
Instead, I'd rather just get the playlist directly.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I create directories with numbered files for the library and playlist,
this patch creates generic code for reading them during startup.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I do this in another idle task, I also had to give the library a
function to find tracks based on (libid, trackid).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I do this whenever the playlist changes (tracks added, removed or
playlist renumbered). When playlists are deleted I remove the file. I
also remove the file when new_number < cur_number.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
From index.cpp to filter.cpp. I also added in an "is_visible()"
function for testing visibility of tracks.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Right now I just add and remove songs from the index as they are added
and removed from the playlist.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Right now I just pause after the current song, but I eventually plan on
adding controls to pause after N songs.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I keep a counter that is decremented after every call to next(). When
it reaches zero, pause after loading the next song.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Delete the library file
- Remove tracks from each playlist
- Notify the renderer that tracks have been removed
- Notify library drivers that the path has been removed
- Remove the path from the list
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I learned how to set custom gtk_rc styles to configure the idle task
progress bar. Now that it's smaller, I also moved it to the very bottom
of the window.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Renumber when new playlists are either added or removed
- Finding nth playlist is much easier now
- Insert new playlists right before the library
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to make it less stack-ish because I was getting confused.
Turns out people don't think people have a hard time thinking about song
order starting from the end... :-(
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I was using connect_after(), but somewhere along the line the space bar
was getting lost. Instead, I only connect the number keys using
g_signal_connect_after() so treeview shortcuts continue to work.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This gives me the correct answer right away. I also re-set the time
whenever a new playlist is created to keep the new tab from changing the
time.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
0 - 9: Switch to playlist N
L / l: Switch to library
R / r: Switch to recent songs
N / n: Play next song
P / p: Play previous song
Escape: Give main window focus
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This way people can see what has played recently and directly select
from a list. Generic playlist classes are awesome!
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Only works for new sets
- Set a callback function when created
- Add a right-click menu to the ocarina treeview
- Remove songs from playlist when picking next song
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I now only have a single instance of the control buttons, so the old
code can be removed now. The footer has been completely replaced by now.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
- Change WriteTask() to take an extra void pointer argument
- Pass library path pointer through WriteTask
- Store tracks to file named after library id.
- Remove newline from tags
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I plan on using (library, track) ids as a way of storing playlists. I
made both counters unsigned ints, since I'm willing to bet that people
won't have 4,294,967,295 songs or library paths...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'll eventually allow more playlists to be stacked, but for now picking
from the library is easy. I may eventually add in a way to pick
sequentially from a set.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I now have direct access to the track that was selected, so I created a
dummy function to play it (to be filled in soon).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
For sets, I keep a sorted list and merge-sort the new songs. I also
created insert_prepare() and insert_done() functions to tell the UI that
we are about to insert (this gives me a chance to call the
freeze_child_notify() and thaw_child_notify() in GTK).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Right now this must be set when a new playlist is constructed. I can
eventually change this to use a default name based on what type of
playlist has been created.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The renderer doesn't actually render anything yet, but it is statically
defined in ocarina/playlist.cpp and it will eventually display the
library.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This makes more sense to me conceptually than having a class called
PlaylistRenderer. I also commented out a lot of code, so the renderer
doesn't do anything right now.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to re-implement my old SongList class as a PlaylistRenderer,
so for now I create a new directory and a new header file.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I sort the subset of tracks to be added, and then use insertion sort to
add them to the playlist object.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't pull out the audio properties yet, but I do find artist, album,
title and everything else that I can.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This will eventually be used to determine if the track is visible based
on library path visibility.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This gives the UI a chance to set the new path or new size. I also
updated Ocarina to show the library path size in its liststore row.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This also removed the other `typedef sid_t` left in the header file.
I'll re-add in functions and variables as I need them, and hopefully
keep things working more efficiently.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I was using the sid_t to lookups for tracks and library paths. I think
I can simplify things by storing pointers in the UI rather than using
id numbers. This will give me direct access to whatever it is I want to
manipulate.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I created a new "list_dir()" function to recursively list directory
contents. I plan on using this to find songs to add to the library, but
it could also be modified to read playlists and library paths in the
appdir.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Whenever a task is queued, I increment a counter. When it is run, I
increment a different counter. This allows me to track the idle queue
completion percentage. I also created a progress bar for Ocarina to
display in the toes of the footer.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This allows other tools to be written to modify the library of a
currently running program without having to create a library driver
instance.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The set_tab_packing() function is deprecated, so I might as well just
use the real way to do this...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to need a polling loop for the progress bar. I might as well
only create one poll() function that is used to do everything...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I want to eventually use this to create a library file for each library
path. The "visible" field will be used to enable and disable different
paths during run time.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The UI calls the library::add_path() function to create a new
LibraryPath structure to be managed by the library.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I want to gradually re-add everything and clean it up as I go along. To
help with this, I comment out the old code so I can use it as a
reference while writing new code.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to use a ribbon-ish interface for the footer and work the
settings pages in with the now playing widgets to make things easier to
find. Right now, I created everything with placeholders.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm not using a notebook as the main widget anymore. I'm also setting
the content directly, rather than getting the widget from the body code
and setting it in the window code.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I need to do some hacky things if the maximization changes. First, I
need to track the old (w, h) values and restore them in the preferences
since the configure-event will resize the window before the maximize
signal is given. Next, I need to ignore the next configure event since
it'll overwrite the preferences with the size of the window when it was
maximized.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This is one of the first things that happens when initializing libsaria.
This also allows me to remove the remaining commented out code from the
preferences file.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I made a WriteTask class to use for saving files. This allows me to
create a file in the appdir and write out the new preferences if they've
changed.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I do this from the window init function using default values, rather
than pass it as a parameter to the init function.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I combined the ocarina.h and gtk.h header files into one single file. I
also began writing new window managing code under a window namespace for
code separation.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I'm going to replace my old path lookup code with something designed
around accessing files in a pre-set directory. I'm also moving back to
putting files in the home diretory, rather than the XDG_CONFIG directory.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Instead, I pass a string with the name of the application being run.
This will be used to have separate applications using libsaria.
This commit also comments out most of the libsaria and ocarina init
functions until I can revise and clean up everything.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I eventually plan on creating more cpp binaries that link with libsaria
for pipe actions and other things. It's helpful to only initialize the
parts of libsaria that I intend to use.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The UI shortcuts may remove songs from the queue with no way of
notifying the stack layer. The UI should call the stack_top_pop()
function to check if the top playlist is empty and ready for removal.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Now renderers don't need to track this on their own, and renderers will
update as tracks are added.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Not all renderers are created dynamically, so I made a way of telling
the playlist system if renderers should be deleted.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I only allow one queue instance right now, but this allows me to remove
the queue directory since it is no longer needed. I also removed the
QUEUE_REFRESH callback since all this is handled through the libsaria
playlist code. All that's left is reloading saved playlists on startup.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Right now it's just for a single queue, but I should be able to expand
this once I enable more stacking in the backend.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This allows for bookkeeping and other cleanup (schedule playlist
removal, remove from UI, and so on).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This patch does two things. First, I remove the Page class and let each
notebook page manage itself. Second, I created functions to add the
header and footer to a GtkWidget and then prepend the page in the
notebook (so it adds pages as if it was a stack).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
My goal is to eventually pick songs from whatever is on top of the
playlist stack. Right now, only the library is added and no songs are
picked.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Unfortunately, this doesn't hide the queue when empty anymore. I
probably won't see this behavior again until I create the stack.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This replaces the "remove id" ability and replaces it with a "remove
index" ability. Removing an index will remove the correct song in the
case that the same song has been added multiple times. I also modified
the UI to remove rows at a specific index.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I can get everything I need using playlists and renderers, so I can
safely remove this bit of code (I never really liked it anyway...). I
have to keep around the queue::size() function for a little bit longer,
since choosing the next song still uses it.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't need these now that I have playlist renderers, so I might as
well rip out the code while I'm thinking about it.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Rather than exposing iterator functions, I now have a function to walk
the playlist and call the renderer insert() function for each track.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This class will be given a Playlist and will be in charge of calling
Playlist functions. I eventually plan on expanding this to allow the
playlist to call renderer functions instead of using my current callback
system.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't have filtering enabled right now, but I may change my mind in
the future. Might as well prepare now...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I don't think I'll need this once I implement dynamic, stackable
playlists, but for now I need a way of scheduling the idle task.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I put in a generic IOTask function. I'm sure this could eventually be
expanded to open and pass the appropriate stream to functions using this
task.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
If both PL_RANDOM and PL_SEQUENTIAL are enabled, then I want to check
the random preference to determine what to do.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I do this if PL_RANDOM is set before checking PL_SEQUENTIAL. I still
need to respond to the case that both flags are set...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The improved next() function will increment the current iterator to the
next visible song. If no songs are visible, then it moves to the next
song on the list. The PL_DRAIN flags is then checked, and if draining
is enabled then the current track is removed from the list before
returning.
This patch also switches over the library sequential next function to
use the lib_playlist version.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I can do this easier with library::lookup() since this avoids having to
loop on the entire track_list.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
get_info() performed a loop over all library paths and over each track
in each path to find the requested sid_t. I now keep a map sid_t ->
Track * to make finding the track easier and faster.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This allows more direct access to each item in the list. It also speeds
up sorting, since I don't need to keep looking up the same tracks over
and over again in the library.
Siged-off-by: Bryan Schumaker <bjschuma@gmail.com>
With Playlists this code is no longer needed. I'll remove more of this
code once I've updated the UI.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
With this change, my old queue code no longer saves itself. Instead, it
only sends out QUEUE_REFRESH notifications.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Note that this follows the broken implementation used by the queue. It
will remove all ids with the given values rather than the ones at a
specifix index. This will be fixed later when I update the UI to make
it Playlist-aware.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I replace the old queue iterator functions with calls to the queue
playlist object that way I don't need to modify the UI. This creates a
common iterator that can be used by all playlists.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
My goal is to slowly phase in use of a Playlist class. This patch
begins this effort by creating the Playlist class and changing the queue
code to load queue.q as a playlist in addition to the queue's hardcoded
list.
Signed-off-by: Bryan Schumake <bjschuma@gmail.com>
I want to pass a playlist argument through during playlist construction,
so I changed the LoadTask to handle it.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
My environment variables were set in a way that the path
/home/bjschuma/~/.config/saria-debug was being returned as the working
directory. Obviously this is wrong, so I changed the function to make
better use of default values when finding the directory.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
When installing through the PKGBUILD, a non-blank DESTDIR is used and
the ocarina-* scripts are configured to use the package directory rather
than the installed directory.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Rather than resetting the preference, it's easier to call the add_alsa()
function if the preference is set. This also cuts down on startup
warnings!
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I want these to help check for memory leaks and other problems. Maybe
one day I can run them through Jenkins!
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I've found that without ALSA enabled, the about-to-finish will hang. To
solve this, I only enable it when ALSA is enabled.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
GTK was printing a warning whenever a non-escaped string was hovered
over. The tooltip was also empty.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This function returns a newly allocated string, so I can't set it
directly to a C++ string since this will leak memory. Instead, I need
to keep the char* pointer around to free it.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Each script acts as an ocarina sub-command, and each write through the
ocarina-write-pipe script. Note that these scripts cannot be run
directly, and need to run through a processor in the Sconstruct file to
set the correct paths.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
My Sconstruct now supports installing a debug build to
/usr/lib/ocarina-debug and launching through ocarina-debug. This should
allow me to test pipe related scripts
The UI now passes in a string to use as the filename. In addition, I
store the filename and remove it when the application is closed. If the
pipe already exists, then I return the path without creating a new one.
Pipes will only be removed by the application that creates them.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I save the song before refreshing the library so I can scroll back to
it. This way the user isn't interrupted too much...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I want to store the currently selected row and go back there after a
refresh or a filter. This allows me to find the current songid and
scroll back to it later.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I eventually want to be able to choose what columns are shown, so I need
them added to the treeview but now shown.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The tooltip is the filepath of the selected track. This should help me
figure out what some non-tagged tracks are...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I keep one array instead of two, and I store more information for each
array entry. I can then find the size of the array for the number of
columns, and I can add new columns without having to modify the allay,
treestore and liststore.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The library only needs to refresh if new tracks were found, so don't do
anything if nothing new has been added.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I eventually only want the library page to have this header, but setting
this up allows me to remove the "switched page" logic that may (or may
not) have been causing problems.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I created a new preference for "Using ALSA" that people can set if they
want to use extra alsa features. This should allow the UI to provide a
dropdown list of outputs that users can select. Once a UI is in place,
users can play music either on their computer speakers or pipe it out to
their blu ray players (or other device).
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
After listening to a long queue, I noticed that there were problems
re-realizing widgets after moving the footer to a different page (the
header might have the same problem?). I decided to fix this issue by
creating a new footer instance for each notebook page.
If I do the same thing for the page header then I can get rid of the
"move this widget from page X to page Y" logic AND allow pages to use
their own custom header AND allow for separate library and queue
filters.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
If the text is "play", "pause", or "next" then I call the appropriate
libsaria function. I eventually plan on adding more commands so bash
can act as a generic remote control, but for now this is a good start!
To use: `echo play > ~/.config/saria[-debug]/saria.pipe` after creating
the fifo (see scripts/makepipe).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I should eventually work this into the main ocarina script somehow, but
probably not until I get generic commands going. `ocarina openpipe`
should do...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I have a hard time remembering how this works, so instead I leave it up
to the UI to determine how to handle this event running from multiple
threads.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Gstreamer uses multiple threads, and doing gtk calls outside the main
thread can lead to X11 errors. I get around this by creating a new
signal to respond to by the main loop.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
The new code is a bit simpler, and it correctly fills in the list of
library paths during startup (I still have no idea why this didn't
happen with the old code).
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This makes it easier to loop over all the library paths without needing
to know anything about implementation. I modified the update functions
to use the new way, so it should be ready for use by the UI.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I moved ocarina over to the new system, so the old one can go away now
since it isn't thread safe and nothing uses it anymore.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I use the gdk threading functions to change my gtk code. This should
create fewer UI inconsistencies whenever anything changes, and it should
also allow me to trigger TRACK_LOADED from a new gstreamer thread.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
Rather than keeping a map of function pointers, I want the UI to
register a single function that takes a callback_t as an argument. From
there, the UI can decide the best way to handle callback lookups (such
as grabbing a lock before changing anything). At the very least, a
switch statement or array lookup should be faster than searching a map.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
When either HOME or XDG_CONFIG_HOME are unset getenv() can return NULL.
C++ strings don't like being set to NULL, so we need to check for this
case.
Bryan: Edited Sconstruct and commit message.
Signed-off-by: Josh Larson <theMutatedShrimp@gmail.com>
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I found it was calling itself over and over again, rather than calling
the stdlib rand(). This wasn't the desired behavior...
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
I have been doing this as part of the release process, but it's slightly
easier to do it as a commit after. I was having too much trouble
keeping the hash correct in the last few months.
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
If a file has been moved to another location in the same library root
the new location won't be added since it'll have the same inode number.
The track would then be removed during the library validation step. I
switch the order for correctness.
It was being initialized with '==' instead of '=', so the for loop was
always causing a segmentation fault. This was caused by commit
180707a6c2
Author: Bryan Schumaker <bjschuma@gmail.com>
Date: Thu Dec 29 22:08:53 2011 -0500
libsaria: Remove redundant code
Nothing needs to call this function anymore. I also cleaned
up the header file a bit.
I check two things during this step:
1) Does the file still exist?
2) Does the file have the same inode number?
If the answer to either of these is "no", then the track is removed from
the library.
Tracks only need to be unlisted from the library list when they are
manually removed by the user. Trying to do this during shutdown lead do
a segfault because the library's file_list had already been removed when
I tried to access it.
This allows me to create only one Track() instance for each song in the
library. Before this, a Track() was being created and then copied when
adding new songs to the library. I thought this was wasteful, so now
each song is only created once.
I removed the old list functions while I was at it. I also changed the
next() function in the controls.cpp file to work with filepaths so the
library and queue won't have to load the chosen file themselves.
I use these to fill in the UI list for the library. I think this will
be easier to use (and cleaner) than passing a function pointer to a
for_each loop.
This is useful for sorting the library when filling in the list, since I
do many comparisons with the same artists and albums. This beats having
to lowercase them every time!
Each cache miss will add a new word to either the format cache or the
substring cache. I can look at the size of the caches to determine the
number of misses rather than keep track of this with a new variable.
I don't care about the order of words for indexing, and I don't need
duplicates either. Formatting to a unique set of words should make
things a little faster.
This keeps the index up-to-date with the library. Tracks are indexed as
they are scanned, then the current filter string is run through the
index again to update it.
Without this, pressing "play" on an empty library will cause an error.
The recovery code will then try to pick a new song, and fail (since
there are no tracks to choose from). It will then try to play, cause an
error and repeat forever.
I need to get the next file out of the library or queue without changing
it immediately. I then queue it up in the gstreamer pipeline so it will
play automatically when the current track finishes.
I look for an audio-changed signal and push this to the message bus. I
then use the message to send out the TRACK_LOADED callback to the UI.
This should be even more useful for gapless playback.
It was only getting filtered when new songs were added to it and never
unfiltered. This was somewhat confusing for me, and not very useful
since the only visible songs were the last ones added. I fixed this by
creating an init option to enable filtering on songlists.
Unlike my old version, this menu item is a check box that shows the user
the current 'pause after' state. This should be more useful and less
frustrating / confusing now.
What if you want to leave and a good song starts playing? This solves
the problem by loading the next song, but not playing it so the user can
go away and listen to it when they come back.
I had a test function, but it wasn't being called. I connected the
widget to the activate signal and improved the function to list the rows
that are currently selected.
I was doing 50, but I think I can handle 100. I also defined a constant
at the top of the file to make it easier to change this value again in
the future.
I return the number of visible songs, so if the user has entered a
filter string then I return the size of the results set. If we're not
filtered then I return the size of the playlist.
This is an index of every substring in the (artist, album, title) tags
of the library. This should be easier to work with than regular
expression based filtering since I don't need to compare every key with
every search term.
Right now this will only be triggered when the library is loaded from
disk. Once I get farther I can easily create a function to index a
track as it is added to the library (so I won't need to reindex
everything during this case)
If we are unable to open the preferences file we shouldn't try to read
from it. This led to a segmentation fault when compiled in release
mode, but for some reason it worked when compiled in debug mode?
I wanted something simple, so after some google searching I decided to
go with a "plain language" version of the GLP v2. This means I can
understand it, since it's not written in lawyerspeak.
relative paths can't be trusted once the program has been installed. To
get around this, I assume that the install directory has been configured
correctly and then point to images located in the subdirectory next to
the executable.
Random hasn't been implemented in libsaria yet, but I can still create
the button to test preferences. The random button should set itself to
the value store in the preferences file.
Button 1 seeks by 10 seconds either forward or backward, button 2 seeks
to an absolute position. I initally wanted to switch the behavior of
these two buttons, but for now I'll just have to get used to the GTK
defaults.
I sort by artist / album / track, so I need to check each of these
fields in order. It would be nice if I could expand numbers into words
for some tags (3 Doors Down, Matchbox 20 and so on), but I'm happy with
what I have right now.
Pointers to a TrackTag structure are easier to pass around than the
TrackTag structure, so this should speed up sorting. Also it removes
duplicated memory between the LibraryPaths and the play_list.
Lookup by id will be slighly slower, but now I will have one list for
each path that can be merged together and sorted to represent the
library. This sounds like a good tradeoff to me, especially since I can
store an iterator to the current track when deciding what to play next.
This will give me much faster access to song for the current track.
I need to store the inode somewhere if I want to use a linked list to
store LibraryPath data. I currently have a map <ino_t, TrackTag>, so
the obvious choice is to store the inode in the TrackTag structure.
I was using a map, but the map required duplicating the library path
everywhere. Except for removing a path, I don't ever need to look up a
specific path by name, so why bother optimizing this case? Iterating
over a linked list should be more efficient (and easier to comprehend)
I switched over to using pango <span> tags to set font properties to
make the text larger. I decided that the title will be bigger than
artist and album, so I can't have one generic function for setting the
label properties. Instead, I divided it up into one function for each
label.
This function is used to access how far into the song the current audio
position is. The value is returned as a percentage of the total length
for easy use by the UI.
I always want to find tags if it's possible. Since I already have a way
to find the tags, it's fairly simple to tag a random file and pass the
result back to the UI.
Namespaces make code easier to follow, and remove the need to mangle the
beginning of function names by using ocarina_*() or libsaria_*(). In
other words: "namespaces are one honking good idea. Let's have more of
them!"
The SourceModel declares an insert() function that is called when
filling the list. I have defined this function in a way that the list
will be filled in through repeated calls to insert()
The source model class is used to more tightly control how songs are
inserted into the UI. I provide an insert() function that the library's
for_each() function can take advantage of. This allows me to directly
insert songs into the UI rather than having to use a static function as
the "middle man"
I want controls to be on the same level as the artist / album / title
labels. This will be more compact, and it won't waste a lot of empty
space above the labels and next to the controls.
This is just an initial implementation, so it's not very good right now.
It does give all the information, though. That's a plus. I also set
the artist / album / playlist whenever a SONG_LOADED callback is given.
This function will generate a Track object based on the current file
stored by the audio. I then pass this object to to provided function so
the UI can be updated.
It really should go into the include directory. I don't want to use
relative paths to include header files in a subdirectory... I don't know
why I even did it in the first place!
This cleans up the idle task code a lot, and reduces the size of
ocarina.bin to less than 1MB (with full debugging). It probably won't
stay there long...
I combined reference counting with the get_footer() function to make
using it easier (no manual reference counting). put_footer() will
deallocate the widget if the reference count is 0 (this is already done
by the g_object_unref() function) so it should work in a sane way.
Calling the remove() function will destroy the footer if it has no other
references. To prevent this, I need to call g_object_ref() add a
reference to the widget.
If the user no longer wishes to track a certain path, they can remove it
from the library. Note: it is unsafe to remove a path from the library
while that path is being scanned. This could potentially lead to a
segmentation fault.
The code was a bit messy and didn't make use of namespaces very well.
By converting to a set of functions (instead of a class) I can use
each function as a function pointer if I want to. I am also able to
remove libsaria/library.cpp since this was just a set of wrapper
functions to the old static class functions.
I plan on storing all my preferences there rather than creating my own
save directory. This will keep things consistent with other
applications the user may have.
I register the idle task when there are events in the idle queue and I
remove the idle task once those events have been processed. This should
cut down on CPU usage when nothing is happening.
When the first task is queued, I trigger a callback so the UI can start
processing when idle. I return the size of the queue from both
run_task() and queue_task() so the UI knows when to stop processing
callbacks.
I don't actually perform a library update at this point, but I do create
a new task and add it to the update queue. When the run_task() function
is called, the task is removed from the queue and deleted.
A text button will use a slightly larger image to make it easier to see.
This also gives me an opportunity to add some help text to describe what
the button does.
I think ocarina/ is a better name for this directory, and now that I've
named the executable "ocarina.bin" I can do this again. I also added
functions for creating a page footer with the basic controls.
This will include code for seeking and getting the current position in
the song. Right now I just have a function for resetting the position
to the beginning of the song.
Now I won't have to keep using libsaria_get() to access parts of
libsaria. This should also cut down on the number of things that need
to be recompiled when libsaria is changed...
When the button is created, it should be set to the current volume of
the gstreamer pipeline. If I don't do this, the icon will default to a
"muted" status.
I moved it from the generic button.cpp file to the controls.cpp file to
keep everything together. I also changed the button list to use the new
show / hide functions.
I moved all the button code into a new subdirectory. From there, I
moved the play button code into a file named controls.cpp. This should
help clean up button code.
Scons will track changes to my include/ directory better than make will.
I also have an easier time understanding the Sconstruct file than I did
with Makefiles.
I hide the play button when music is playing and show it when music has
been stopped. I hide the pause button when music is not playing and
show it when music has been stopped. This can give the effect of one
button replacing the other.
These functions will be triggered when the libsaria play or pause
functions are called. Right now they just print out a message, but I
plan on doing more.
I would rather have the front end program load the song rather than
assuming that everything should be loaded right away. This also gives
front end programs a chance to register callbacks before loading.
I have created generic functions for registering and triggering
callbacks. New callbacks can be added by creating a new constant in the
callback_t enum.
play() and pause() now return true or false base on if the state change
request succeeds or fails. This can be used later to determine if a
callback should be triggered.
I stop playback, and seek to the beginning. I do this as to different
function calls in the Libsaria class so callbacks will still trigger
(once they have been implemented).
Ocarina is a simple GTK+ and GStreamer based music player written to let you listen to your music without getting in the way.
### Git
Ocarina is tracked with Git, and can be cloned from the following sources:
* http://git.nowheycreamery.com/anna/ocarina.git
* git://git.nowheycreamery.com/anna/ocarina.git
##### Branches
* [master]
* The most recent release. This branch does not change frequently.
* [next]
* Changes that will be included in the next release. This branch is for testing and bugfixing.
### Building
Ocarina uses `cmake`to control the build process. After cloning the code, run `cmake .` to generate the Makefile. Compile using `make`
##### CMake Options
Ocarina supports the following options, which can be passed to `cmake` through `cmake -D<option>=<ON|OFF>`. For example, `cmake -DCONFIG_DEBUG=ON` would enable debugging.
* CONFIG_DEBUG
* Compile with debugging symbols enabled
* CONFIG_TESTING_VERBOSE
* Enable extra output when running unit tests
* CONFIG_TESTING_GUI
* Enable running GUI unit tests
* CONFIG_TESTING_ARTWORK
* Enable unit tests that fetch album artwork
### Running
Once compiled, Ocarina can be run by invoking `bin/ocarina` on the command line.
##### Runtime options
The following options can be passed to Ocarina during startup
* -h, --help
* Print help message and exit
* -n, --next
* Tell a running Ocarina instance to play the next track
* - P, --pause
* Tell a running Ocarina instance to pause playback
* -p, --play
* Tell a running Ocarina instance to start playback
* -N, --previous
* Tell a running Ocarina instance to play the previous track
* -t, --toggle
* Tell a paused Ocarina instance to begin playback, or tell a playing Ocarina instance to pause.
* -v, --version
* Print Ocarina version and exit
### Installing
Running `make install` will install Ocarina for use by all users. There is currently no "uninstall" option.
### Testing
Running `make tests` will compile and run the Ocarina unit tests. See the CMake Options section above for additional testing options.