43 #define STATE_FILE "playlist-state"
45 #define ENTER pthread_mutex_lock (& mutex)
46 #define LEAVE pthread_mutex_unlock (& mutex)
48 #define RETURN(...) do { \
49 pthread_mutex_unlock (& mutex); \
53 #define ENTER_GET_PLAYLIST(...) ENTER; \
54 Playlist * playlist = lookup_playlist (playlist_num); \
58 #define ENTER_GET_ENTRY(...) ENTER_GET_PLAYLIST (__VA_ARGS__); \
59 Entry * entry = lookup_entry (playlist, entry_num); \
72 char * formatted, *
title, * artist, * album;
99 static pthread_mutex_t
mutex = PTHREAD_MUTEX_INITIALIZER;
100 static pthread_cond_t
cond = PTHREAD_COND_INITIALIZER;
154 entry->
tuple = tuple;
238 g_slice_free (
Entry, entry);
244 GINT_TO_POINTER (preferred),
NULL,
NULL))
294 g_list_free (playlist->
queued);
300 for (
int count = 0; count < length; count ++)
303 playlist->
number = at + count;
315 for (
int count = 0; count < length; count ++)
318 entry->
number = at + count;
350 hook_call (
"playlist update", GINT_TO_POINTER (level));
406 int level = u->
level;
415 if (playlist_num >= 0)
439 for (GList * node =
scan_list; node; node = node->next)
451 for (GList * node =
scan_list; node; node = node->next)
454 if (item->
entry == entry)
463 for (GList * node =
scan_list; node; node = node->next)
574 pthread_cond_broadcast (&
cond);
606 if (! entry || entry->
failed)
609 if ((need_decoder && ! entry->
decoder) || (need_tuple && ! entry->
tuple))
629 if (! entry || entry->
failed)
632 if ((need_decoder && ! entry->
decoder) || (need_tuple && ! entry->
tuple))
670 active_playlist = playing_playlist =
NULL;
765 playing_playlist =
NULL;
777 int unique_id =
playlist->unique_id;
786 int num = p ? p->
number : -1;
864 int list = active_playlist ? active_playlist->
number : -1;
880 if (playlist == playing_playlist)
883 if (playing_playlist)
890 if (playlist && ! playlist->
position)
893 position_changed =
TRUE;
909 if (position_changed)
910 hook_call (
"playlist position", GINT_TO_POINTER (playlist_num));
924 int list = playing_playlist ? playing_playlist->
number: -1;
948 for (list = 0; list < count; list ++)
973 if (entry && update_shuffle)
1000 if (at < 0 || at > entries)
1008 for (
int i = 0; i < number; i ++)
1028 for (
int count = 0; count < number; count ++)
1047 if (at < 0 || at > entries)
1049 if (number < 0 || number > entries - at)
1050 number = entries -
at;
1053 playlist->position->number < at + number)
1055 position_changed =
TRUE;
1062 playlist->focus->number < at + number)
1064 if (at + number < entries)
1072 for (
int count = 0; count < number; count ++)
1092 if (position_changed &&
get_bool (
NULL,
"advance_on_delete"))
1098 if (position_changed)
1099 hook_call (
"playlist position", GINT_TO_POINTER (playlist_num));
1126 Tuple * tuple = entry ? entry->
tuple :
NULL;
1145 char * * title,
char * * artist,
char * * album,
bool_t fast)
1166 int length = entry ? entry->
length : 0;
1183 hook_call (
"playlist position", GINT_TO_POINTER (playlist_num));
1199 int first = INT_MAX;
1234 if (
entry->selected == selected)
1237 entry->selected = selected;
1264 int selected_count =
playlist->selected_count;
1273 int first = entries, last = 0;
1275 for (
int count = 0; count < entries; count ++)
1289 playlist->selected_count = entries;
1298 if (first < entries)
1308 if (!
entry->selected || ! distance)
1312 int shift = 0, center, top, bottom;
1316 for (center = entry_num; center > 0 && shift > distance; )
1319 if (!
entry->selected)
1325 for (center = entry_num + 1; center < entries && shift < distance; )
1328 if (!
entry->selected)
1333 top = bottom = center;
1335 for (
int i = 0; i < top; i ++)
1338 if (
entry->selected)
1342 for (
int i = entries; i > bottom; i --)
1345 if (
entry->selected)
1351 for (
int i = top; i < center; i ++)
1354 if (!
entry->selected)
1358 for (
int i = top; i < bottom; i ++)
1361 if (
entry->selected)
1365 for (
int i = center; i < bottom; i ++)
1368 if (!
entry->selected)
1383 return playlist->
focus;
1387 for (
int search = playlist->
focus->
number + 1; search < entries; search ++)
1394 for (
int search = playlist->
focus->
number; search --;)
1421 position_changed =
TRUE;
1429 int before = 0, after = 0;
1432 for (
int count = 0; count < entries; count++)
1467 if (position_changed &&
get_bool (
NULL,
"advance_on_delete"))
1473 if (position_changed)
1474 hook_call (
"playlist position", GINT_TO_POINTER (playlist_num));
1488 for (
int count = entries; count --; )
1508 for (
int count = entries; count --; )
1516 for (
int count = 0; count < entries; count++)
1536 for (
int i = 0; i < entries; i ++)
1538 int j = i + rand () % (entries - i);
1559 for (
int count = 0; count < entries; count++)
1566 for (
int i = 0; i <
playlist->selected_count; i ++)
1568 int j = i + rand () % (
playlist->selected_count - i);
1576 for (
int count = 0; count < entries; count++)
1599 static int compare_cb (
const void * _a,
const void * _b,
void * _data)
1601 const Entry *
a = _a, *
b = _b;
1612 b->formatted ? b->formatted : b->filename);
1618 return a->
number - b->number;
1636 for (
int count = 0; count < entries; count++)
1646 for (
int count = 0; count < entries; count++)
1662 for (
int count = 0; count < entries; count ++)
1671 "metadata scanning is still in progress (or has been disabled)."));
1680 (
const char *
a,
const char *
b))
1691 (
const Tuple * a,
const Tuple * b))
1715 (
const char * a,
const char * b))
1726 (
const Tuple * a,
const Tuple * b))
1738 (
const char * a,
const char * b))
1762 for (
int count = 0; count < entries; count++)
1796 for (
int count = 0; count < entries; count ++)
1823 for (
int playlist_num = 0; playlist_num < num_playlists; playlist_num ++)
1828 for (
int entry_num = 0; entry_num < num_entries; entry_num ++)
1832 if (! strcmp (entry->
filename, filename))
1846 int64_t length =
playlist->total_length;
1853 int64_t length =
playlist->selected_length;
1860 int count = g_list_length (
playlist->queued);
1887 int first = entries, last = 0;
1889 for (
int count = 0; count < entries; count++)
1906 if (first < entries)
1916 GList * node = g_list_nth (
playlist->queued, at);
1917 int entry_num = node ? ((
Entry *) node->data)->number : -1;
1934 int first = entries, last = 0;
1938 while (
playlist->queued && number --)
1950 GList * anchor = g_list_nth (
playlist->queued, at - 1);
1954 while (anchor->next && number --)
1966 if (first < entries)
1977 int first = entries, last = 0;
1979 for (GList * node =
playlist->queued; node; )
1981 GList * next = node->next;
1995 if (first < entries)
2006 for (
int count = 0; count < entries; count ++)
2045 hook_call (
"playlist position", GINT_TO_POINTER (playlist_num));
2057 for (count = 0; count < entries; count ++)
2078 choice = rand () % choice;
2080 for (count = 0; ; count ++)
2103 for (
int count = 0; count < entries; count ++)
2137 if (hint >= entries)
2163 hook_call (
"playlist position", GINT_TO_POINTER (playlist_num));
2175 int entry_num = entry ? entry->
number : -1;
2205 Tuple * tuple = entry ? entry->
tuple :
NULL;
2228 int length = entry ? entry->
length : 0;
2236 if (! playing_playlist || ! playing_playlist->
position)
2255 FILE * handle = fopen (path,
"w");
2260 fprintf (handle,
"active %d\n", active_playlist ? active_playlist->
number : -1);
2261 fprintf (handle,
"playing %d\n", playing_playlist ? playing_playlist->
number : -1);
2268 fprintf (handle,
"playlist %d\n", playlist_num);
2271 fprintf (handle,
"filename %s\n", playlist->
filename);
2275 if (playlist == playing_playlist)
2282 fprintf (handle,
"resume-time %d\n", playlist->
resume_time);
2296 if (! fgets (parse_key,
sizeof parse_key, handle))
2299 char * space = strchr (parse_key,
' ');
2304 parse_value = space + 1;
2306 char * newline = strchr (parse_value,
'\n');
2313 return (parse_value && ! strcmp (parse_key, key) && sscanf (parse_value,
"%d", value) == 1);
2318 return (parse_value && ! strcmp (parse_key, key)) ?
str_get (parse_value) :
NULL;
2327 FILE * handle = fopen (path,
"r");
2344 while (
parse_integer (
"playlist", & playlist_num) && playlist_num >= 0 &&
2364 if (position >= 0 && position < entries)
static char * title_format
void playlist_insert_with_id(int at, int id)
int playlist_get_playing(void)
static char * title_from_tuple(Tuple *tuple)
static Entry * lookup_entry(Playlist *playlist, int entry_num)
int playlist_get_unique_id(int playlist_num)
Index Index play fast playlist_entry_get_title
void playlist_reverse(int playlist_num)
void playlist_reformat_titles(void)
int(* CompareFunc)(const void *a, const void *b)
bool_t playlist_next_song(int playlist_num, bool_t repeat)
static bool_t shuffle_prev(Playlist *playlist)
void playlist_sort_selected_by_filename(int playlist_num, int(*compare)(const char *a, const char *b))
char * playback_entry_get_title(void)
int playlist_by_unique_id(int id)
int playlist_queue_find_entry(int playlist_num, int entry_num)
static int compare_cb(const void *_a, const void *_b, void *_data)
static void parse_next(FILE *handle)
void playlist_queue_insert(int playlist_num, int at, int entry_num)
EXPORT Index * index_new(void)
int playlist_get_active(void)
EXPORT void index_insert(Index *index, int at, void *value)
static float a[EQ_BANDS][2]
EXPORT void index_delete(Index *index, int at, int count)
static Playlist * playing_playlist
static Playlist * active_playlist
void playlist_entry_insert_batch_raw(int playlist_num, int at, Index *filenames, Index *tuples, Index *decoders)
int playlist_selected_count(int playlist_num)
void playlist_sort_selected_by_title(int playlist_num, int(*compare)(const char *a, const char *b))
char * get_string(const char *section, const char *name)
int playlist_get_temporary(void)
static bool_t shuffle_next(Playlist *playlist)
const char PluginHandle decoder const char PluginHandle decoder const char PluginHandle decoder void const PreferencesWidget int
void playlist_rescan(int playlist_num)
static bool_t update(void *unused)
bool_t playlist_entry_get_selected(int playlist_num, int entry_num)
static float b[EQ_BANDS][2]
static bool_t scan_queue_next_entry(void)
int playlist_entry_count(int playlist_num)
char * playback_entry_get_filename(void)
void playlist_entry_set_selected(int playlist_num, int entry_num, bool_t selected)
static void scan_queue_entry(Playlist *playlist, Entry *entry)
EXPORT int index_count(Index *index)
static void entry_set_tuple(Playlist *playlist, Entry *entry, Tuple *tuple)
static char * parse_string(const char *key)
bool_t playlist_prev_song(int playlist_num)
EXPORT void index_merge_insert(Index *first, int at, Index *second)
void playlist_queue_insert_selected(int playlist_num, int at)
void playlist_sort_by_title(int playlist_num, int(*compare)(const char *a, const char *b))
static Playlist * lookup_playlist(int playlist_num)
static bool_t parse_integer(const char *key, int *value)
int playlist_queue_get_entry(int playlist_num, int at)
int playback_entry_get_length(void)
void playlist_queue_delete(int playlist_num, int at, int number)
void playlist_set_focus(int playlist_num, int entry_num)
char * str_ref(char *str)
EXPORT void index_allocate(Index *index, int size)
void playlist_rescan_file(const char *filename)
void playlist_entry_describe(int playlist_num, int entry_num, char **title, char **artist, char **album, bool_t fast)
void playlist_reorder(int from, int to, int count)
void playlist_delete(int playlist_num)
static void entry_free(Entry *entry)
#define ENTER_GET_ENTRY(...)
int playlist_shift(int playlist_num, int entry_num, int distance)
static Playlist * playlist_new(int id)
void playlist_trigger_scan(void)
void playlist_load_state(void)
Tuple * playback_entry_get_tuple(void)
Tuple * scan_request_get_tuple(ScanRequest *request)
Tuple * playlist_entry_get_tuple(int playlist_num, int entry_num, bool_t fast)
static void change_playback(bool_t can_play)
static GList * scan_list_find_request(ScanRequest *request)
PluginHandle * playback_entry_get_decoder(void)
char * playlist_get_title(int playlist_num)
int playlist_updated_range(int playlist_num, int *at, int *count)
void playlist_select_all(int playlist_num, bool_t selected)
static void playlist_rescan_real(int playlist_num, bool_t selected)
static Entry * get_playback_entry(bool_t need_decoder, bool_t need_tuple)
void playlist_set_filename(int playlist_num, const char *filename)
EXPORT void * index_get(Index *index, int at)
EXPORT void index_append(Index *index, void *value)
void playlist_set_active(int playlist_num)
ScanRequest * scan_request(const char *filename, int flags, PluginHandle *decoder, ScanCallback callback)
EXPORT void index_sort_with_data(Index *index, int(*compare)(const void *a, const void *b, void *data), void *data)
EXPORT void tuple_unref(Tuple *tuple)
static GHashTable * unique_id_table
static void sort_selected(Playlist *playlist, CompareData *data)
static void number_playlists(int at, int length)
Index Index play fast fast playlist_entry_get_length
bool_t get_bool(const char *section, const char *name)
static Entry * entry_new(char *filename, Tuple *tuple, PluginHandle *decoder)
static void entry_set_failed(Playlist *playlist, Entry *entry)
int64_t playlist_get_selected_length(int playlist_num)
void playlist_save_state(void)
char * playlist_entry_get_filename(int playlist_num, int entry_num)
int playlist_get_blank(void)
bool_t playlist_update_pending(void)
void playlist_entry_delete(int playlist_num, int at, int number)
bool_t playlist_get_modified(int playlist_num)
static void scan_check_complete(Playlist *playlist)
static Entry * get_entry(int playlist_num, int entry_num, bool_t need_decoder, bool_t need_tuple)
EXPORT char * tuple_format_title(Tuple *tuple, const char *format)
static int next_unique_id
void str_unref(char *str)
EXPORT void index_free(Index *index)
static char * parse_value
static void shuffle_reset(Playlist *playlist)
EXPORT void index_copy_set(Index *source, int from, Index *target, int to, int count)
void playlist_sort_by_tuple(int playlist_num, int(*compare)(const Tuple *a, const Tuple *b))
const char * get_path(int id)
EXPORT void event_queue_cancel(const char *name, void *data)
void playlist_set_position(int playlist_num, int entry_num)
bool_t playlist_scan_in_progress(int playlist_num)
bool_t drct_get_paused(void)
static pthread_cond_t cond
#define event_queue(n, d)
static void scan_schedule(void)
static void queue_update(int level, int list, int at, int count)
int playback_entry_get_position(void)
EXPORT void index_copy_append(Index *source, int from, Index *target, int count)
static bool_t next_song_locked(Playlist *playlist, bool_t repeat, int hint)
EXPORT Tuple * tuple_new_from_filename(const char *filename)
Allocates a new #Tuple structure, setting filename/URI related fields based on the given filename arg...
void playback_entry_set_tuple(Tuple *tuple)
void playlist_rescan_selected(int playlist_num)
EXPORT void index_set(Index *index, int at, void *value)
void playlist_set_modified(int playlist_num, bool_t modified)
EXPORT void index_move(Index *index, int from, int to, int count)
static void scan_restart(void)
static int resume_playlist
void describe_song(const char *name, const Tuple *tuple, char **_title, char **_artist, char **_album)
EXPORT void hook_call(const char *name, void *data)
void playlist_set_title(int playlist_num, const char *title)
void playlist_reverse_selected(int playlist_num)
EXPORT Tuple * tuple_ref(Tuple *tuple)
EXPORT TupleValueType tuple_get_value_type(const Tuple *tuple, int nfield, const char *field)
Returns TupleValueType of given #Tuple field.
void playlist_randomize_selected(int playlist_num)
Basic Tuple handling API.
static bool_t entries_are_scanned(Playlist *playlist, bool_t selected)
void playback_play(int seek_time, bool_t pause)
static void scan_cancel(Entry *entry)
#define ENTER_GET_PLAYLIST(...)
static void scan_finish(ScanRequest *request)
Index Index play playlist_entry_get_decoder
int playlist_queue_count(int playlist_num)
Track length in milliseconds.
int playlist_get_focus(int playlist_num)
char * playlist_get_filename(int playlist_num)
void interface_show_error(const char *message)
int playlist_get_position(int playlist_num)
void playlist_set_playing(int playlist_num)
void playlist_delete_selected(int playlist_num)
void playlist_insert(int at)
void playlist_randomize(int playlist_num)
static void number_entries(Playlist *playlist, int at, int length)
char * str_get(const char *str)
static GList * scan_list_find_playlist(Playlist *playlist)
PluginHandle * scan_request_get_decoder(ScanRequest *request)
static const char *const temp_title
void playlist_sort_selected_by_tuple(int playlist_num, int(*compare)(const Tuple *a, const Tuple *b))
static int new_unique_id(int preferred)
static char parse_key[512]
static void set_position(Playlist *playlist, Entry *entry, bool_t update_shuffle)
int64_t playlist_get_total_length(int playlist_num)
void playlist_sort_by_filename(int playlist_num, int(*compare)(const char *a, const char *b))
static Entry * find_unselected_focus(Playlist *playlist)
static void sort(Playlist *playlist, CompareData *data)
void playlist_queue_delete_selected(int playlist_num)
static pthread_mutex_t mutex
void playlist_resume(void)
static GList * scan_list_find_entry(Entry *entry)
static const char *const default_title
bool_t drct_get_playing(void)
static void playlist_free(Playlist *playlist)
EXPORT int tuple_get_int(const Tuple *tuple, int nfield, const char *field)
Returns integer associated to #Tuple field.
static void entry_set_tuple_real(Entry *entry, Tuple *tuple)