static Tuple * wv_probe_for_tuple(const char * filename, VFSFile * fd) { WavpackContext *ctx; Tuple *tu; char error[1024]; ctx = WavpackOpenFileInputEx(&wv_readers, fd, NULL, error, OPEN_TAGS, 0); if (ctx == NULL) return NULL; AUDDBG("starting probe of %p\n", (void *) fd); vfs_rewind(fd); tu = tuple_new_from_filename(filename); vfs_rewind(fd); tag_tuple_read(tu, fd); tuple_set_int(tu, FIELD_LENGTH, NULL, ((uint64_t) WavpackGetNumSamples(ctx) * 1000) / (uint64_t) WavpackGetSampleRate(ctx)); tuple_set_str(tu, FIELD_CODEC, NULL, "WavPack"); char * quality = wv_get_quality (ctx); tuple_set_str (tu, FIELD_QUALITY, NULL, quality); str_unref (quality); WavpackCloseFile(ctx); AUDDBG("returning tuple %p for file %p\n", (void *) tu, (void *) fd); return tu; }
static void add_text (Tuple * tuple, int field, const char * value) { char * cur = tuple_get_str (tuple, field, NULL); if (cur) { SPRINTF (both, "%s, %s", cur, value); tuple_set_str (tuple, field, NULL, both); } else tuple_set_str (tuple, field, NULL, value); str_unref(cur); }
Tuple *psf2_tuple(const char *filename, VFSFile *file) { Tuple *t; corlett_t *c; void *buf; int64_t sz; vfs_file_get_contents (filename, & buf, & sz); if (!buf) return NULL; if (corlett_decode(buf, sz, NULL, NULL, &c) != AO_SUCCESS) return NULL; t = tuple_new_from_filename(filename); tuple_set_int(t, FIELD_LENGTH, NULL, c->inf_length ? psfTimeToMS(c->inf_length) + psfTimeToMS(c->inf_fade) : -1); tuple_set_str(t, FIELD_ARTIST, NULL, c->inf_artist); tuple_set_str(t, FIELD_ALBUM, NULL, c->inf_game); tuple_set_str(t, -1, "game", c->inf_game); tuple_set_str(t, FIELD_TITLE, NULL, c->inf_title); tuple_set_str(t, FIELD_COPYRIGHT, NULL, c->inf_copy); tuple_set_str(t, FIELD_QUALITY, NULL, _("sequenced")); tuple_set_str(t, FIELD_CODEC, NULL, "PlayStation 1/2 Audio"); tuple_set_str(t, -1, "console", "PlayStation 1/2"); free(c); free(buf); return t; }
static Tuple * read_tuple (const gchar * filename, VFSFile * file) { Tuple * tuple = NULL; AVFormatContext * ic = open_input_file (filename, file); if (ic) { CodecInfo cinfo; if (find_codec (ic, & cinfo)) { tuple = tuple_new_from_filename (filename); tuple_set_int (tuple, FIELD_LENGTH, ic->duration / 1000); tuple_set_int (tuple, FIELD_BITRATE, ic->bit_rate / 1000); if (cinfo.codec->long_name) tuple_set_str (tuple, FIELD_CODEC, cinfo.codec->long_name); if (ic->metadata) read_metadata_dict (tuple, ic->metadata); if (cinfo.stream->metadata) read_metadata_dict (tuple, cinfo.stream->metadata); } close_input_file (ic); } return tuple; }
static Tuple *probe_for_tuple(const char *filename, VFSFile *file) { int song = -1; unsigned char module[ASAPInfo_MAX_MODULE_LENGTH]; int module_len; ASAPInfo *info = NULL; Tuple *tuple = NULL; int songs; int duration; int year; #if _AUD_PLUGIN_VERSION >= 10 char *real_filename = filename_split_subtune(filename, &song); if (real_filename != NULL) filename = real_filename; #endif module_len = load_module(filename, file, module); if (module_len > 0) { info = ASAPInfo_New(); if (info != NULL && ASAPInfo_Load(info, filename, module, module_len)) tuple = tuple_new_from_filename(filename); } #if _AUD_PLUGIN_VERSION >= 10 g_free(real_filename); #endif if (tuple == NULL) { ASAPInfo_Delete(info); return NULL; } tuple_set_nonblank(tuple, FIELD_ARTIST, ASAPInfo_GetAuthor(info)); tuple_set_nonblank(tuple, FIELD_TITLE, ASAPInfo_GetTitleOrFilename(info)); tuple_set_nonblank(tuple, FIELD_DATE, ASAPInfo_GetDate(info)); tuple_set_str(tuple, FIELD_CODEC, NULL, "ASAP"); songs = ASAPInfo_GetSongs(info); if (song > 0) { tuple_set_int(tuple, FIELD_SUBSONG_ID, NULL, song); tuple_set_int(tuple, FIELD_SUBSONG_NUM, NULL, songs); song--; } else { if (songs > 1) { #if _AUD_PLUGIN_VERSION >= 37 tuple_set_subtunes(tuple, songs, NULL); #else tuple->nsubtunes = songs; #endif } song = ASAPInfo_GetDefaultSong(info); } duration = ASAPInfo_GetDuration(info, song); if (duration > 0) tuple_set_int(tuple, FIELD_LENGTH, NULL, duration); year = ASAPInfo_GetYear(info); if (year > 0) tuple_set_int(tuple, FIELD_YEAR, NULL, year); ASAPInfo_Delete(info); return tuple; }
Tuple *gsf_get_song_tuple(const gchar *filename, VFSFile *file) { char tag[50001]; char tmp_str[256]; const gchar *fn; Tuple *ti; fn = g_filename_from_uri(filename, NULL, NULL); ti = tuple_new_from_filename(fn); psftag_readfromfile((void*)tag, fn); if (!psftag_getvar(tag, "title", tmp_str, sizeof(tmp_str)-1)) { tuple_set_str(ti, FIELD_TITLE, NULL, tmp_str); } if (!psftag_getvar(tag, "artist", tmp_str, sizeof(tmp_str)-1)) { tuple_set_str(ti, FIELD_ARTIST, NULL, tmp_str); } if (!psftag_getvar(tag, "game", tmp_str, sizeof(tmp_str)-1)) { tuple_set_str(ti, FIELD_ALBUM, NULL, tmp_str); } if (!psftag_getvar(tag, "year", tmp_str, sizeof(tmp_str)-1)) { tuple_set_str(ti, FIELD_DATE, NULL, tmp_str); } if (!psftag_getvar(tag, "copyright", tmp_str, sizeof(tmp_str)-1)) { tuple_set_str(ti, FIELD_COPYRIGHT, NULL, tmp_str); } if (!psftag_getvar(tag, "tagger", tmp_str, sizeof(tmp_str)-1)) { tuple_set_str(ti, -1, "tagger", tmp_str); } if (!psftag_raw_getvar(tag, "length", tmp_str, sizeof(tmp_str)-1)) { tuple_set_int(ti, FIELD_LENGTH, NULL, LengthFromString(tmp_str) + FadeLength); } if (!psftag_getvar(tag, "comment", tmp_str, sizeof(tmp_str)-1)) { tuple_set_str(ti, FIELD_COMMENT, NULL, tmp_str); } tuple_set_str(ti, FIELD_CODEC, NULL, "GameBoy Advanced Audio (GSF)"); tuple_set_str(ti, FIELD_QUALITY, NULL, "sequenced"); return ti; }
static void set_field_str_from_entry (Tuple * tuple, int fieldn, GtkWidget * widget) { const char * text = gtk_entry_get_text ((GtkEntry *) widget); if (text[0]) tuple_set_str (tuple, fieldn, NULL, text); else tuple_unset (tuple, fieldn, NULL); }
static void set_tuple_str(Tuple *tuple, const gint nfield, const gchar *field, vorbis_comment *comment, gchar *key) { gchar *str = vorbis_comment_query(comment, key, 0); if (str != NULL) { gchar *tmp = str_to_utf8(str); tuple_set_str(tuple, nfield, field, tmp); g_free(tmp); } }
static bool_t audpl_load (const char * path, VFSFile * file, char * * title, Index * filenames, Index * tuples) { ReadState * state = malloc (sizeof (ReadState)); state->file = file; state->cur = state->buf; state->len = 0; char * key, * val; if (! read_key (state, & key, & val) || strcmp (key, "title")) { free (state); return FALSE; } * title = str_get (val); bool_t readed = read_key (state, & key, & val); while (readed && ! strcmp (key, "uri")) { char * uri = str_get (val); Tuple * tuple = NULL; while ((readed = read_key (state, & key, & val)) && strcmp (key, "uri")) { if (! tuple) tuple = tuple_new_from_filename (uri); if (! strcmp (key, "empty")) continue; int field = tuple_field_by_name (key); TupleValueType type = tuple_field_get_type (field); if (field < 0) break; if (type == TUPLE_STRING) tuple_set_str (tuple, field, NULL, val); else if (type == TUPLE_INT) tuple_set_int (tuple, field, NULL, atoi (val)); } index_append (filenames, uri); index_append (tuples, tuple); } free (state); return TRUE; }
/* * Return song information Tuple */ static void xs_get_song_tuple_info(Tuple *tuple, xs_tuneinfo_t *info, gint subTune) { gchar *tmpStr; tmpStr = str_to_utf8(info->sidName); tuple_set_str(tuple, FIELD_TITLE, NULL, tmpStr); g_free(tmpStr); tmpStr = str_to_utf8(info->sidComposer); tuple_set_str(tuple, FIELD_ARTIST, NULL, tmpStr); g_free(tmpStr); tmpStr = str_to_utf8(info->sidCopyright); tuple_set_str(tuple, FIELD_COPYRIGHT, NULL, tmpStr); g_free(tmpStr); tuple_set_str(tuple, FIELD_CODEC, NULL, info->sidFormat); #if 0 switch (info->sidModel) { case XS_SIDMODEL_6581: tmpStr = "6581"; break; case XS_SIDMODEL_8580: tmpStr = "8580"; break; case XS_SIDMODEL_ANY: tmpStr = "ANY"; break; default: tmpStr = "?"; break; } tuple_set_str(tuple, -1, "sid-model", tmpStr); #endif /* Get sub-tune information, if available */ if (subTune < 0 || info->startTune > info->nsubTunes) subTune = info->startTune; if (subTune > 0 && subTune <= info->nsubTunes) { gint tmpInt = info->subTunes[subTune - 1].tuneLength; tuple_set_int(tuple, FIELD_LENGTH, NULL, (tmpInt < 0) ? -1 : tmpInt * 1000); #if 0 tmpInt = info->subTunes[subTune - 1].tuneSpeed; if (tmpInt > 0) { switch (tmpInt) { case XS_CLOCK_PAL: tmpStr = "PAL"; break; case XS_CLOCK_NTSC: tmpStr = "NTSC"; break; case XS_CLOCK_ANY: tmpStr = "ANY"; break; case XS_CLOCK_VBI: tmpStr = "VBI"; break; case XS_CLOCK_CIA: tmpStr = "CIA"; break; default: g_snprintf(tmpStr2, sizeof(tmpStr2), "%dHz", tmpInt); tmpStr = tmpStr2; break; } } else tmpStr = "?"; tuple_set_str(tuple, -1, "sid-speed", tmpStr); #endif } else subTune = 1; tuple_set_int(tuple, FIELD_SUBSONG_NUM, NULL, info->nsubTunes); tuple_set_int(tuple, FIELD_SUBSONG_ID, NULL, subTune); tuple_set_int(tuple, FIELD_TRACK_NUMBER, NULL, subTune); }
static void decode_genre (Tuple * tuple, const unsigned char * data, int size) { int numericgenre; char * text = decode_text_frame (data, size); if (text == NULL) return; if (text[0] == '(') numericgenre = atoi (text + 1); else numericgenre = atoi (text); if (numericgenre > 0) tuple_set_str (tuple, FIELD_GENRE, NULL, convert_numericgenre_to_text (numericgenre)); else tuple_set_str (tuple, FIELD_GENRE, NULL, text); g_free (text); return; }
static Tuple *metronom_probe_for_tuple(const char * filename, VFSFile *fd) { Tuple *tuple = tuple_new_from_filename(filename); metronom_t metronom; char *tmp = NULL; if (metronom_get_cp(filename, &metronom, &tmp)) tuple_set_str(tuple, FIELD_TITLE, tmp); str_unref(tmp); return tuple; }
static void decode_comment (Tuple * tuple, const unsigned char * data, int size) { char * lang, * type, * value; if (! decode_comment_frame (data, size, & lang, & type, & value)) return; TAGDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value); if (! type[0]) /* blank type == actual comment */ tuple_set_str (tuple, FIELD_COMMENT, NULL, value); g_free (lang); g_free (type); g_free (value); }
static void tuple_attach_cdtext(Tuple *tuple, Track *track, int tuple_type, int pti) { Cdtext *cdtext; const char *text; cdtext = track_get_cdtext(track); if (cdtext == NULL) return; text = cdtext_get(pti, cdtext); if (text == NULL) return; tuple_set_str (tuple, tuple_type, text); }
static Tuple *tone_probe_for_tuple(const gchar *filename, VFSFile *fd) { Tuple *tuple = tuple_new_from_filename(filename); gchar *tmp; if (tuple == NULL) return NULL; if ((tmp = tone_title(filename)) != NULL) { tuple_set_str(tuple, FIELD_TITLE, NULL, tmp); g_free(tmp); } return tuple; }
static void decode_private_info (Tuple * tuple, const unsigned char * data, int size) { char * text = g_strndup ((const char *) data, size); if (!strncmp(text, "WM/", 3)) { char *separator = strchr(text, 0); if (separator == NULL) goto DONE; char * value = separator + 1; if (!strncmp(text, "WM/MediaClassPrimaryID", 22)) { if (!memcmp(value, PRIMARY_CLASS_MUSIC, 16)) tuple_set_str (tuple, -1, "media-class", "Music"); if (!memcmp(value, PRIMARY_CLASS_AUDIO, 16)) tuple_set_str (tuple, -1, "media-class", "Audio (non-music)"); } else if (!strncmp(text, "WM/MediaClassSecondaryID", 24)) { if (!memcmp(value, SECONDARY_CLASS_AUDIOBOOK, 16)) tuple_set_str (tuple, -1, "media-class", "Audio Book"); if (!memcmp(value, SECONDARY_CLASS_SPOKENWORD, 16)) tuple_set_str (tuple, -1, "media-class", "Spoken Word"); if (!memcmp(value, SECONDARY_CLASS_NEWS, 16)) tuple_set_str (tuple, -1, "media-class", "News"); if (!memcmp(value, SECONDARY_CLASS_TALKSHOW, 16)) tuple_set_str (tuple, -1, "media-class", "Talk Show"); if (!memcmp(value, SECONDARY_CLASS_GAMES_CLIP, 16)) tuple_set_str (tuple, -1, "media-class", "Game Audio (clip)"); if (!memcmp(value, SECONDARY_CLASS_GAMES_SONG, 16)) tuple_set_str (tuple, -1, "media-class", "Game Soundtrack"); } else { TAGDBG("Unrecognised tag %s (Windows Media) ignored\n", text); } } else { TAGDBG("Unable to decode private data, skipping: %s\n", text); } DONE: g_free (text); }
static void associate_string (Tuple * tuple, int field, const char * customfield, const unsigned char * data, int size) { char * text = decode_text_frame (data, size); if (text == NULL || ! text[0]) { g_free (text); return; } if (customfield != NULL) TAGDBG ("Custom field %s = %s.\n", customfield, text); else TAGDBG ("Field %i = %s.\n", field, text); tuple_set_str (tuple, field, customfield, text); g_free (text); }
Tuple *vtx_get_song_tuple_from_vtx(const gchar * filename, ayemu_vtx_t * in) { Tuple *out = tuple_new_from_filename(filename); tuple_set_str(out, FIELD_ARTIST, NULL, in->hdr.author); tuple_set_str(out, FIELD_TITLE, NULL, in->hdr.title); tuple_set_int(out, FIELD_LENGTH, NULL, in->hdr.regdata_size / 14 * 1000 / 50); tuple_set_str(out, FIELD_GENRE, NULL, (in->hdr.chiptype == AYEMU_AY) ? "AY chiptunes" : "YM chiptunes"); tuple_set_str(out, FIELD_ALBUM, NULL, in->hdr.from); tuple_set_str(out, -1, "game", in->hdr.from); tuple_set_str(out, FIELD_QUALITY, NULL, "sequenced"); tuple_set_str(out, FIELD_CODEC, NULL, in->hdr.tracker); tuple_set_str(out, -1, "tracker", in->hdr.tracker); tuple_set_int(out, FIELD_YEAR, NULL, in->hdr.year); return out; }
static void read_metadata_dict (Tuple * tuple, AVDictionary * dict) { for (int i = 0; i < ARRAY_LEN (metaentries); i ++) { const ffaudio_meta_t * m = & metaentries[i]; AVDictionaryEntry * entry = NULL; for (int j = 0; ! entry && m->keys[j]; j ++) entry = av_dict_get (dict, m->keys[j], NULL, 0); if (entry && entry->value) { if (m->ttype == TUPLE_STRING) tuple_set_str (tuple, m->field, entry->value); else if (m->ttype == TUPLE_INT) tuple_set_int (tuple, m->field, atoi (entry->value)); } } }
static Tuple * get_tuple_for_vorbisfile(OggVorbis_File * vorbisfile, const gchar *filename) { Tuple *tuple; gint length; vorbis_comment *comment = NULL; tuple = tuple_new_from_filename(filename); length = vfs_is_streaming (vorbisfile->datasource) ? -1 : ov_time_total (vorbisfile, -1) * 1000; /* associate with tuple */ tuple_set_int(tuple, FIELD_LENGTH, length); if ((comment = ov_comment(vorbisfile, -1)) != NULL) { gchar *tmps; set_tuple_str(tuple, FIELD_TITLE, comment, "title"); set_tuple_str(tuple, FIELD_ARTIST, comment, "artist"); set_tuple_str(tuple, FIELD_ALBUM, comment, "album"); set_tuple_str(tuple, FIELD_GENRE, comment, "genre"); set_tuple_str(tuple, FIELD_COMMENT, comment, "comment"); if ((tmps = vorbis_comment_query(comment, "tracknumber", 0)) != NULL) tuple_set_int(tuple, FIELD_TRACK_NUMBER, atoi(tmps)); if ((tmps = vorbis_comment_query (comment, "date", 0)) != NULL) tuple_set_int (tuple, FIELD_YEAR, atoi (tmps)); } vorbis_info * info = ov_info (vorbisfile, -1); tuple_set_format (tuple, "Ogg Vorbis", info->channels, info->rate, info->bitrate_nominal / 1000); tuple_set_str(tuple, FIELD_MIMETYPE, "application/ogg"); return tuple; }
Tuple *flac_probe_for_tuple(const char *filename, VFSFile *fd) { AUDDBG("Probe for tuple.\n"); Tuple *tuple = NULL; FLAC__Metadata_Iterator *iter; FLAC__Metadata_Chain *chain; FLAC__StreamMetadata *metadata = NULL; FLAC__Metadata_ChainStatus status; FLAC__StreamMetadata_VorbisComment_Entry *entry; char *key; char *value; tuple = tuple_new_from_filename(filename); tuple_set_str(tuple, FIELD_CODEC, NULL, "Free Lossless Audio Codec (FLAC)"); tuple_set_str(tuple, FIELD_QUALITY, NULL, _("lossless")); chain = FLAC__metadata_chain_new(); if (!FLAC__metadata_chain_read_with_callbacks(chain, fd, io_callbacks)) goto ERR; iter = FLAC__metadata_iterator_new(); FLAC__metadata_iterator_init(iter, chain); do { switch (FLAC__metadata_iterator_get_block_type(iter)) { case FLAC__METADATA_TYPE_VORBIS_COMMENT: if (FLAC__metadata_iterator_get_block_type(iter) == FLAC__METADATA_TYPE_VORBIS_COMMENT) { metadata = FLAC__metadata_iterator_get_block(iter); AUDDBG("Vorbis comment contains %d fields\n", metadata->data.vorbis_comment.num_comments); AUDDBG("Vendor string: %s\n", metadata->data.vorbis_comment.vendor_string.entry); entry = metadata->data.vorbis_comment.comments; for (int i = 0; i < metadata->data.vorbis_comment.num_comments; i++, entry++) { if (FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(*entry, &key, &value) == false) AUDDBG("Could not parse comment\n"); else { parse_comment(tuple, key, value); free(key); free(value); } } } break; case FLAC__METADATA_TYPE_STREAMINFO: metadata = FLAC__metadata_iterator_get_block(iter); /* Calculate the stream length (milliseconds) */ if (metadata->data.stream_info.sample_rate == 0) { FLACNG_ERROR("Invalid sample rate for stream!\n"); tuple_set_int(tuple, FIELD_LENGTH, NULL, -1); } else { tuple_set_int(tuple, FIELD_LENGTH, NULL, (metadata->data.stream_info.total_samples / metadata->data.stream_info.sample_rate) * 1000); AUDDBG("Stream length: %d seconds\n", tuple_get_int(tuple, FIELD_LENGTH, NULL)); } int64_t size = vfs_fsize(fd); if (size == -1 || metadata->data.stream_info.total_samples == 0) tuple_set_int(tuple, FIELD_BITRATE, NULL, 0); else { int bitrate = 8 * size * (int64_t) metadata->data.stream_info.sample_rate / metadata->data.stream_info.total_samples; tuple_set_int(tuple, FIELD_BITRATE, NULL, (bitrate + 500) / 1000); } break; default: ; } } while (FLAC__metadata_iterator_next(iter)); FLAC__metadata_iterator_delete(iter); FLAC__metadata_chain_delete(chain); return tuple; ERR: status = FLAC__metadata_chain_status(chain); FLAC__metadata_chain_delete(chain); FLACNG_ERROR("An error occured: %s\n", FLAC__Metadata_ChainStatusString[status]); return tuple; }
static void set_tuple_str(Tuple *tuple, const gint nfield, vorbis_comment *comment, gchar *key) { tuple_set_str (tuple, nfield, vorbis_comment_query (comment, key, 0)); }
static void xspf_add_file (xmlNode * track, const gchar * filename, const gchar * base, Index * filenames, Index * tuples) { xmlNode *nptr; gchar *location = NULL; Tuple * tuple = NULL; for (nptr = track->children; nptr != NULL; nptr = nptr->next) { if (nptr->type == XML_ELEMENT_NODE) { if (!xmlStrcmp(nptr->name, (xmlChar *)"location")) { /* Location is a special case */ gchar *str = (gchar *)xmlNodeGetContent(nptr); if (strstr (str, "://") != NULL) location = str_get (str); else if (str[0] == '/' && base != NULL) { const gchar * colon = strstr (base, "://"); if (colon != NULL) location = str_printf ("%.*s%s", (gint) (colon + 3 - base), base, str); } else if (base != NULL) { const gchar * slash = strrchr (base, '/'); if (slash != NULL) location = str_printf ("%.*s%s", (gint) (slash + 1 - base), base, str); } xmlFree(str); } else { /* Rest of the nodes are handled here */ gint i; gboolean isMeta; xmlChar *findName; if (!xmlStrcmp(nptr->name, (xmlChar *)"meta")) { isMeta = TRUE; findName = xmlGetProp(nptr, (xmlChar *)"rel"); } else { isMeta = FALSE; findName = xmlStrdup(nptr->name); } for (i = 0; i < xspf_nentries; i++) if ((xspf_entries[i].isMeta == isMeta) && !xmlStrcmp(findName, (xmlChar *)xspf_entries[i].xspfName)) { xmlChar *str = xmlNodeGetContent(nptr); switch (xspf_entries[i].type) { case TUPLE_STRING: if (! tuple) tuple = tuple_new (); tuple_set_str(tuple, xspf_entries[i].tupleField, NULL, (gchar *)str); break; case TUPLE_INT: if (! tuple) tuple = tuple_new (); tuple_set_int(tuple, xspf_entries[i].tupleField, NULL, atol((char *)str)); break; default: break; } xmlFree(str); break; } xmlFree(findName); } } } if (location != NULL) { if (tuple) tuple_set_filename (tuple, location); index_append(filenames, location); index_append(tuples, tuple); } else if (tuple) tuple_unref (tuple); }
static void tuple_set_nonblank(Tuple *tuple, int nfield, const char *value) { if (value[0] != '\0') tuple_set_str(tuple, nfield, NULL, value); }
/* thread safe */ static Tuple * make_tuple (const gchar * filename, VFSFile * file) { Tuple *tuple = NULL; gint trackno; g_mutex_lock (mutex); if (trackinfo == NULL) refresh_trackinfo (TRUE); if (trackinfo == NULL) goto DONE; if (!strcmp (filename, "cdda://")) { tuple = tuple_new_from_filename (filename); gint subtunes[n_audio_tracks]; gint i = 0; /* only add the audio tracks to the playlist */ for (trackno = firsttrackno; trackno <= lasttrackno; trackno++) if (cdda_track_audiop (pcdrom_drive, trackno)) subtunes[i ++] = trackno; tuple_set_subtunes (tuple, n_audio_tracks, subtunes); goto DONE; } trackno = find_trackno_from_filename (filename); if (trackno < firsttrackno || trackno > lasttrackno) { warn ("Track %d not found.\n", trackno); goto DONE; } if (!cdda_track_audiop (pcdrom_drive, trackno)) { warn ("Track %d is a data track.\n", trackno); goto DONE; } tuple = tuple_new_from_filename (filename); tuple_set_format (tuple, _("Audio CD"), 2, 44100, 1411); if (strlen (trackinfo[trackno].performer)) { tuple_set_str (tuple, FIELD_ARTIST, NULL, trackinfo[trackno].performer); } if (strlen (trackinfo[0].name)) { tuple_set_str (tuple, FIELD_ALBUM, NULL, trackinfo[0].name); } if (strlen (trackinfo[trackno].name)) { tuple_set_str (tuple, FIELD_TITLE, NULL, trackinfo[trackno].name); } tuple_set_int (tuple, FIELD_TRACK_NUMBER, NULL, trackno); tuple_set_int (tuple, FIELD_LENGTH, NULL, calculate_track_length (trackinfo[trackno]. startlsn, trackinfo[trackno]. endlsn)); if (strlen (trackinfo[trackno].genre)) { tuple_set_str (tuple, FIELD_GENRE, NULL, trackinfo[trackno].genre); } DONE: g_mutex_unlock (mutex); return tuple; }