static void decode_rva (Tuple * tuple, const guchar * data, gint size) { const gchar * domain; gint channel, adjustment, adjustment_unit, peak, peak_unit; if (memchr (data, 0, size) == NULL) return; domain = (const gchar *) data; TAGDBG ("RVA domain: %s\n", domain); size -= strlen (domain) + 1; data += strlen (domain) + 1; while (size > 0) { if (! decode_rva_block (& data, & size, & channel, & adjustment, & adjustment_unit, & peak, & peak_unit)) break; if (channel != 1) /* specific channel? */ continue; if (tuple_get_value_type (tuple, FIELD_GAIN_GAIN_UNIT, NULL) == TUPLE_INT) adjustment = adjustment * (gint64) tuple_get_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL) / adjustment_unit; else tuple_associate_int (tuple, FIELD_GAIN_GAIN_UNIT, NULL, adjustment_unit); if (peak_unit) { if (tuple_get_value_type (tuple, FIELD_GAIN_PEAK_UNIT, NULL) == TUPLE_INT) peak = peak * (gint64) tuple_get_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL) / peak_unit; else tuple_associate_int (tuple, FIELD_GAIN_PEAK_UNIT, NULL, peak_unit); } if (! strcasecmp (domain, "album")) { tuple_associate_int (tuple, FIELD_GAIN_ALBUM_GAIN, NULL, adjustment); if (peak_unit) tuple_associate_int (tuple, FIELD_GAIN_ALBUM_PEAK, NULL, peak); } else if (! strcasecmp (domain, "track")) { tuple_associate_int (tuple, FIELD_GAIN_TRACK_GAIN, NULL, adjustment); if (peak_unit) tuple_associate_int (tuple, FIELD_GAIN_TRACK_PEAK, NULL, peak); } } }
static int tuple_compare_int (const Tuple * a, const Tuple * b, int field) { if (tuple_get_value_type (a, field, NULL) != TUPLE_INT) return (tuple_get_value_type (b, field, NULL) != TUPLE_INT) ? 0 : -1; if (tuple_get_value_type (b, field, NULL) != TUPLE_INT) return 1; int int_a = tuple_get_int (a, field, NULL); int int_b = tuple_get_int (b, field, NULL); return (int_a < int_b) ? -1 : (int_a > int_b); }
static void insert_vorbis_comment (FLAC__StreamMetadata * meta, const char * name, const Tuple * tuple, int field) { TupleValueType type = tuple_field_get_type (field); if (tuple_get_value_type (tuple, field, NULL) != type) return; char * temp; switch (type) { case TUPLE_INT:; int ival = tuple_get_int (tuple, field, NULL); temp = g_strdup_printf ("%s=%d", name, ival); break; case TUPLE_STRING:; char * sval = tuple_get_str (tuple, field, NULL); temp = g_strdup_printf ("%s=%s", name, sval); str_unref (sval); default: return; } FLAC__StreamMetadata_VorbisComment_Entry comment; comment.length = strlen (temp); comment.entry = (unsigned char *) temp; FLAC__metadata_object_vorbiscomment_insert_comment (meta, meta->data.vorbis_comment.num_comments, comment, TRUE); g_free (temp); }
/* builtin-keyword: ${(empty)?}. returns TRUE if <arg> is empty. */ static gboolean tuple_formatter_expression_empty(Tuple *tuple, const gchar *expression) { gboolean ret = TRUE; const gchar *iter; TupleValueType type = tuple_get_value_type(tuple, -1, expression); if (type == TUPLE_UNKNOWN) return TRUE; if (type == TUPLE_INT) return (tuple_get_int(tuple, -1, expression) == 0); iter = tuple_get_string(tuple, -1, expression); if (!iter) return TRUE; while (ret && *iter != '\0') { if (*iter == ' ') iter++; else ret = FALSE; } return ret; }
static bool_t audpl_save (const char * path, VFSFile * file, const char * title, Index * filenames, Index * tuples) { if (! write_key (file, "title", title)) return FALSE; int count = index_count (filenames); for (int i = 0; i < count; i ++) { if (! write_key (file, "uri", index_get (filenames, i))) return FALSE; const Tuple * tuple = tuples ? index_get (tuples, i) : NULL; if (tuple) { int keys = 0; for (int f = 0; f < TUPLE_FIELDS; f ++) { if (f == FIELD_FILE_PATH || f == FIELD_FILE_NAME || f == FIELD_FILE_EXT) continue; TupleValueType type = tuple_get_value_type (tuple, f, NULL); if (type == TUPLE_STRING) { char * str = tuple_get_str (tuple, f, NULL); if (! write_key (file, tuple_field_get_name (f), str)) { str_unref (str); return FALSE; } str_unref (str); keys ++; } else if (type == TUPLE_INT) { char buf[32]; snprintf (buf, sizeof buf, "%d", tuple_get_int (tuple, f, NULL)); if (! write_key (file, tuple_field_get_name (f), buf)) return FALSE; keys ++; } } /* distinguish between an empty tuple and no tuple at all */ if (! keys && ! write_key (file, "empty", "1")) return FALSE; } } return TRUE; }
static void set_gain_info(Tuple *tuple, int field, int unit_field, const char *text) { int value, unit; parse_gain_text(text, &value, &unit); if (tuple_get_value_type(tuple, unit_field, NULL) == TUPLE_INT) value = value * (int64_t) tuple_get_int(tuple, unit_field, NULL) / unit; else tuple_set_int(tuple, unit_field, NULL, unit); tuple_set_int(tuple, field, NULL, value); }
static void add_frameFromTupleInt (const Tuple * tuple, int field, int id3_field, GHashTable * dict) { if (tuple_get_value_type (tuple, field) != TUPLE_INT) { remove_frame (id3_field, dict); return; } char scratch[16]; str_itoa (tuple_get_int (tuple, field), scratch, sizeof scratch); add_text_frame (id3_field, scratch, dict); }
static void add_frameFromTupleInt (const Tuple * tuple, gint field, gint id3_field, mowgli_dictionary_t * dict) { if (tuple_get_value_type (tuple, field, NULL) != TUPLE_INT) { remove_frame (id3_field, dict); return; } gchar scratch[16]; snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, field, NULL)); add_text_frame (id3_field, scratch, dict); }
static void set_entry_int_from_field (GtkWidget * widget, const Tuple * tuple, int fieldn, bool_t editable) { char scratch[32]; if (tuple_get_value_type (tuple, fieldn, NULL) == TUPLE_INT) snprintf (scratch, sizeof scratch, "%d", tuple_get_int (tuple, fieldn, NULL)); else scratch[0] = 0; gtk_entry_set_text ((GtkEntry *) widget, scratch); gtk_editable_set_editable ((GtkEditable *) widget, editable); }
static void infowin_show (gint list, gint entry, const gchar * filename, const Tuple * tuple, PluginHandle * decoder, gboolean updating_enabled) { gchar * tmp; if (infowin == NULL) create_infowin (); else clear_infowin (); current_file = g_strdup (filename); current_decoder = decoder; can_write = updating_enabled; set_entry_str_from_field (entry_title, tuple, FIELD_TITLE, updating_enabled); set_entry_str_from_field (entry_artist, tuple, FIELD_ARTIST, updating_enabled); set_entry_str_from_field (entry_album, tuple, FIELD_ALBUM, updating_enabled); set_entry_str_from_field (entry_comment, tuple, FIELD_COMMENT, updating_enabled); set_entry_str_from_field (gtk_bin_get_child ((GtkBin *) entry_genre), tuple, FIELD_GENRE, updating_enabled); tmp = uri_to_display (filename); gtk_label_set_text ((GtkLabel *) location_text, tmp); g_free (tmp); set_entry_int_from_field (entry_year, tuple, FIELD_YEAR, updating_enabled); set_entry_int_from_field (entry_track, tuple, FIELD_TRACK_NUMBER, updating_enabled); infowin_label_set_text (label_format_name, tuple_get_string (tuple, FIELD_CODEC, NULL)); infowin_label_set_text (label_quality, tuple_get_string (tuple, FIELD_QUALITY, NULL)); if (tuple_get_value_type (tuple, FIELD_BITRATE, NULL) == TUPLE_INT) { tmp = g_strdup_printf (_("%d kb/s"), tuple_get_int (tuple, FIELD_BITRATE, NULL)); infowin_label_set_text (label_bitrate, tmp); g_free (tmp); } else infowin_label_set_text (label_bitrate, NULL); infowin_entry_set_image (image_artwork, list, entry); gtk_window_present ((GtkWindow *) infowin); }
/* processes an expression and optional argument pair. */ gchar * tuple_formatter_process_expr(Tuple *tuple, const gchar *expression, const gchar *argument) { TupleFormatterExpression *expr = NULL; GList *iter; g_return_val_if_fail(tuple != NULL, NULL); g_return_val_if_fail(expression != NULL, NULL); for (iter = tuple_formatter_expr_list; iter != NULL; iter = iter->next) { TupleFormatterExpression *tmp = (TupleFormatterExpression *) iter->data; if (g_str_has_prefix(expression, tmp->name) == TRUE) { expr = tmp; expression += strlen(tmp->name); } } /* ${artist} */ if (expr == NULL && argument == NULL) { TupleValueType type = tuple_get_value_type(tuple, -1, expression); switch(type) { case TUPLE_STRING: return g_strdup(tuple_get_string(tuple, -1, expression)); break; case TUPLE_INT: return g_strdup_printf("%d", tuple_get_int(tuple, -1, expression)); break; case TUPLE_UNKNOWN: default: return NULL; } } else if (expr != NULL) { if (expr->func(tuple, expression) == TRUE && argument != NULL) return tuple_formatter_process_construct(tuple, argument); } return NULL; }
static GValue *tuple_value_to_gvalue(const Tuple * tuple, const gchar * key) { GValue *val; TupleValueType type = tuple_get_value_type((Tuple *) tuple, -1, key); if (type == TUPLE_STRING) { val = g_new0(GValue, 1); g_value_init(val, G_TYPE_STRING); g_value_take_string(val, g_strdup(tuple_get_string((Tuple *) tuple, -1, key))); return val; } else if (type == TUPLE_INT) { val = g_new0(GValue, 1); g_value_init(val, G_TYPE_INT); g_value_set_int(val, tuple_get_int((Tuple *) tuple, -1, key)); return val; } return NULL; }
static char * strdup_tuple_field (const Tuple * tuple, int field) { char * sval, * dup; int ival; switch (tuple_get_value_type (tuple, field, NULL)) { case TUPLE_INT: ival = tuple_get_int (tuple, field, NULL); dup = g_strdup_printf ("%d", ival); break; case TUPLE_STRING: sval = tuple_get_str (tuple, field, NULL); dup = g_strdup (sval); str_unref (sval); break; default: dup = NULL; break; } return dup; }
static gboolean xspf_playlist_save (const gchar * filename, VFSFile * file, const gchar * title, Index * filenames, Index * tuples) { gint entries = index_count (filenames); xmlDocPtr doc; xmlNodePtr rootnode, tracklist; gint count; doc = xmlNewDoc((xmlChar *)"1.0"); doc->charset = XML_CHAR_ENCODING_UTF8; doc->encoding = xmlStrdup((xmlChar *)"UTF-8"); rootnode = xmlNewNode(NULL, (xmlChar *)XSPF_ROOT_NODE_NAME); xmlSetProp(rootnode, (xmlChar *)"version", (xmlChar *)"1"); xmlSetProp(rootnode, (xmlChar *)"xmlns", (xmlChar *)XSPF_XMLNS); /* common */ xmlDocSetRootElement(doc, rootnode); if (title) xspf_add_node (rootnode, TUPLE_STRING, FALSE, "title", title, 0); tracklist = xmlNewNode(NULL, (xmlChar *)"trackList"); xmlAddChild(rootnode, tracklist); for (count = 0; count < entries; count ++) { const gchar * filename = index_get (filenames, count); const Tuple * tuple = index_get (tuples, count); xmlNodePtr track, location; gchar *scratch = NULL; gint scratchi = 0; track = xmlNewNode(NULL, (xmlChar *)"track"); location = xmlNewNode(NULL, (xmlChar *)"location"); xmlAddChild(location, xmlNewText((xmlChar *)filename)); xmlAddChild(track, location); xmlAddChild(tracklist, track); if (tuple != NULL) { gint i; for (i = 0; i < xspf_nentries; i++) { const xspf_entry_t *xs = &xspf_entries[i]; gboolean isOK = (tuple_get_value_type (tuple, xs->tupleField, NULL) == xs->type); switch (xs->type) { case TUPLE_STRING: scratch = tuple_get_str (tuple, xs->tupleField, NULL); if (! scratch) isOK = FALSE; str_unref(scratch); break; case TUPLE_INT: scratchi = tuple_get_int (tuple, xs->tupleField, NULL); break; default: break; } if (isOK) xspf_add_node(track, xs->type, xs->isMeta, xs->xspfName, scratch, scratchi); } } } xmlSaveCtxt * save = xmlSaveToIO (write_cb, close_cb, file, NULL, XML_SAVE_FORMAT); if (! save) goto ERR; if (xmlSaveDoc (save, doc) < 0 || xmlSaveClose (save) < 0) goto ERR; xmlFreeDoc(doc); return TRUE; ERR: xmlFreeDoc (doc); return FALSE; }
static bool_t playlist_load_cue (const char * cue_filename, VFSFile * file, char * * title, Index * filenames, Index * tuples) { void * buffer = NULL; vfs_file_read_all (file, & buffer, NULL); if (! buffer) return FALSE; * title = NULL; Cd * cd = cue_parse_string (buffer); g_free (buffer); if (cd == NULL) return FALSE; int tracks = cd_get_ntrack (cd); if (tracks == 0) return FALSE; Track * current = cd_get_track (cd, 1); if (current == NULL) return FALSE; char * track_filename = track_get_filename (current); if (track_filename == NULL) return FALSE; char * filename = uri_construct (track_filename, cue_filename); Tuple * base_tuple = NULL; bool_t base_tuple_scanned = FALSE; for (int track = 1; track <= tracks; track ++) { if (current == NULL || filename == NULL) return FALSE; if (base_tuple == NULL && ! base_tuple_scanned) { base_tuple_scanned = TRUE; PluginHandle * decoder = aud_file_find_decoder (filename, FALSE); if (decoder != NULL) base_tuple = aud_file_read_tuple (filename, decoder); } Track * next = (track + 1 <= tracks) ? cd_get_track (cd, track + 1) : NULL; char * next_filename = (next != NULL) ? uri_construct (track_get_filename (next), cue_filename) : NULL; bool_t last_track = (next_filename == NULL || strcmp (next_filename, filename)); Tuple * tuple = (base_tuple != NULL) ? tuple_copy (base_tuple) : tuple_new_from_filename (filename); tuple_set_int (tuple, FIELD_TRACK_NUMBER, track); int begin = (int64_t) track_get_start (current) * 1000 / 75; tuple_set_int (tuple, FIELD_SEGMENT_START, begin); if (last_track) { if (base_tuple != NULL && tuple_get_value_type (base_tuple, FIELD_LENGTH) == TUPLE_INT) tuple_set_int (tuple, FIELD_LENGTH, tuple_get_int (base_tuple, FIELD_LENGTH) - begin); } else { int length = (int64_t) track_get_length (current) * 1000 / 75; tuple_set_int (tuple, FIELD_LENGTH, length); tuple_set_int (tuple, FIELD_SEGMENT_END, begin + length); } for (int i = 0; i < ARRAY_LEN (pti_map); i ++) tuple_attach_cdtext (tuple, current, pti_map[i].tuple_type, pti_map[i].pti); index_insert (filenames, -1, str_get (filename)); index_insert (tuples, -1, tuple); current = next; str_unref (filename); filename = next_filename; if (last_track && base_tuple != NULL) { tuple_unref (base_tuple); base_tuple = NULL; base_tuple_scanned = FALSE; } } return TRUE; }
/* builtin-keyword: ${==arg1,arg2}, returns TRUE if <arg1> and <arg2> match. <arg1> and <arg2> can also be raw text, which should be enclosed in "double quotes". */ static gboolean tuple_formatter_expression_match(Tuple *tuple, const gchar *expression) { gchar **args = g_strsplit(expression, ",", 2); gchar *arg1 = NULL, *arg2 = NULL; gint ret; if (args[0][0] == '\"') /* check if arg1 is "raw text" */ { if ( strlen(args[0]) > 1 ) { args[0][strlen(args[0]) - 1] = '\0'; arg1 = g_strdup(&(args[0][1])); args[0][strlen(args[0]) - 1] = '\"'; } else /* bad formatted arg */ return FALSE; } else if (tuple_get_value_type(tuple, -1, args[0]) == TUPLE_UNKNOWN) { g_strfreev(args); return FALSE; } if (args[1][0] == '\"') /* check if arg2 is "raw text" */ { if ( strlen(args[1]) > 1 ) { args[1][strlen(args[1]) - 1] = '\0'; arg2 = g_strdup(&(args[1][1])); args[1][strlen(args[1]) - 1] = '\"'; } else /* bad formatted arg */ return FALSE; } else if (tuple_get_value_type(tuple, -1, args[1]) == TUPLE_UNKNOWN) { g_strfreev(args); return FALSE; } if (!arg1) /* if arg1 is not "raw text", get the tuple value */ { if (tuple_get_value_type(tuple, -1, args[0]) == TUPLE_STRING) arg1 = g_strdup(tuple_get_string(tuple, -1, args[0])); else arg1 = g_strdup_printf("%d", tuple_get_int(tuple, -1, args[0])); } if (!arg2) /* if arg2 is not "raw text", get the tuple value */ { if (tuple_get_value_type(tuple, -1, args[1]) == TUPLE_STRING) arg2 = g_strdup(tuple_get_string(tuple, -1, args[1])); else arg2 = g_strdup_printf("%d", tuple_get_int(tuple, -1, args[1])); } ret = g_ascii_strcasecmp(arg1, arg2); g_free(arg1); g_free(arg2); g_strfreev(args); return ret ? FALSE : TRUE; }