Tuple * xs_probe_for_tuple(const char *filename, VFSFile *fd) { Tuple *tuple; xs_tuneinfo_t *info; int tune = -1; pthread_mutex_lock(&xs_status_mutex); if (!xs_sidplayfp_probe(fd)) { pthread_mutex_unlock(&xs_status_mutex); return NULL; } pthread_mutex_unlock(&xs_status_mutex); /* Get information from URL */ tuple = tuple_new_from_filename (filename); tune = tuple_get_int (tuple, FIELD_SUBSONG_NUM); /* Get tune information from emulation engine */ pthread_mutex_lock(&xs_status_mutex); info = xs_sidplayfp_getinfo (filename); pthread_mutex_unlock(&xs_status_mutex); if (info == NULL) return tuple; xs_get_song_tuple_info(tuple, info, tune); if (xs_cfg.subAutoEnable && info->nsubTunes > 1 && ! tune) xs_fill_subtunes(tuple, info); xs_tuneinfo_free(info); return tuple; }
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 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; }
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 *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; }
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; }
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; }
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 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; }
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, in->hdr.author); tuple_set_str(out, FIELD_TITLE, in->hdr.title); tuple_set_int(out, FIELD_LENGTH, in->hdr.regdata_size / 14 * 1000 / 50); tuple_set_str(out, FIELD_GENRE, (in->hdr.chiptype == AYEMU_AY) ? "AY chiptunes" : "YM chiptunes"); tuple_set_str(out, FIELD_ALBUM, in->hdr.from); tuple_set_str(out, FIELD_QUALITY, _("sequenced")); tuple_set_str(out, FIELD_CODEC, in->hdr.tracker); tuple_set_int(out, FIELD_YEAR, in->hdr.year); return out; }
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 * xs_probe_for_tuple(const gchar *filename, xs_file_t *fd) { Tuple *tuple; xs_tuneinfo_t *info; gint tune = -1; if (xs_status.sidPlayer == NULL || filename == NULL) return NULL; XS_MUTEX_LOCK(xs_status); if (!xs_status.sidPlayer->plrProbe(fd)) { XS_MUTEX_UNLOCK(xs_status); return NULL; } XS_MUTEX_UNLOCK(xs_status); /* Get information from URL */ tuple = tuple_new_from_filename (filename); tune = tuple_get_int (tuple, FIELD_SUBSONG_NUM, NULL); /* Get tune information from emulation engine */ XS_MUTEX_LOCK(xs_status); info = xs_status.sidPlayer->plrGetSIDInfo (filename); XS_MUTEX_UNLOCK(xs_status); if (info == NULL) return tuple; xs_get_song_tuple_info(tuple, info, tune); if (xs_cfg.subAutoEnable && info->nsubTunes > 1 && ! tune) xs_fill_subtunes(tuple, info); xs_tuneinfo_free(info); return tuple; }
static void infowin_update_tuple (void * unused) { Tuple * tuple = tuple_new_from_filename (current_file); set_field_str_from_entry (tuple, FIELD_TITLE, entry_title); set_field_str_from_entry (tuple, FIELD_ARTIST, entry_artist); set_field_str_from_entry (tuple, FIELD_ALBUM, entry_album); set_field_str_from_entry (tuple, FIELD_COMMENT, entry_comment); set_field_str_from_entry (tuple, FIELD_GENRE, gtk_bin_get_child ((GtkBin *) entry_genre)); set_field_int_from_entry (tuple, FIELD_YEAR, entry_year); set_field_int_from_entry (tuple, FIELD_TRACK_NUMBER, entry_track); if (aud_file_write_tuple (current_file, current_decoder, tuple)) { ministatus_display_message (_("Metadata updated successfully")); something_changed = FALSE; gtk_widget_set_sensitive (btn_apply, FALSE); } else ministatus_display_message (_("Metadata updating failed")); tuple_unref (tuple); }
/* * Start playing the given file */ gboolean xs_play_file(InputPlayback *pb, const gchar *filename, VFSFile *file, gint start_time, gint stop_time, gboolean pause) { xs_tuneinfo_t *tmpTune; gint audioBufSize, bufRemaining, tmpLength, subTune = -1; gchar *audioBuffer = NULL, *oversampleBuffer = NULL; Tuple *tmpTuple; assert(pb); assert(xs_status.sidPlayer != NULL); uri_parse (filename, NULL, NULL, NULL, & subTune); /* Get tune information */ XS_MUTEX_LOCK(xs_status); if (! (xs_status.tuneInfo = xs_status.sidPlayer->plrGetSIDInfo (filename))) { XS_MUTEX_UNLOCK(xs_status); return FALSE; } /* Initialize the tune */ if (! xs_status.sidPlayer->plrLoadSID (& xs_status, filename)) { XS_MUTEX_UNLOCK(xs_status); xs_tuneinfo_free(xs_status.tuneInfo); xs_status.tuneInfo = NULL; return FALSE; } gboolean error = FALSE; /* Set general status information */ tmpTune = xs_status.tuneInfo; if (subTune < 1 || subTune > xs_status.tuneInfo->nsubTunes) xs_status.currSong = xs_status.tuneInfo->startTune; else xs_status.currSong = subTune; XSDEBUG("subtune #%i selected (#%d wanted), initializing...\n", xs_status.currSong, subTune); gint channels = (xs_status.audioChannels == XS_CHN_AUTOPAN) ? 2 : xs_status.audioChannels; /* Allocate audio buffer */ audioBufSize = xs_status.audioFrequency * channels * xs_status.audioBitsPerSample / (8 * 4); if (audioBufSize < 512) audioBufSize = 512; audioBuffer = (gchar *) g_malloc(audioBufSize); if (audioBuffer == NULL) { xs_error("Couldn't allocate memory for audio data buffer!\n"); XS_MUTEX_UNLOCK(xs_status); goto xs_err_exit; } if (xs_status.oversampleEnable) { oversampleBuffer = (gchar *) g_malloc(audioBufSize * xs_status.oversampleFactor); if (oversampleBuffer == NULL) { xs_error("Couldn't allocate memory for audio oversampling buffer!\n"); XS_MUTEX_UNLOCK(xs_status); goto xs_err_exit; } } /* Check minimum playtime */ tmpLength = tmpTune->subTunes[xs_status.currSong - 1].tuneLength; if (xs_cfg.playMinTimeEnable && (tmpLength >= 0)) { if (tmpLength < xs_cfg.playMinTime) tmpLength = xs_cfg.playMinTime; } /* Initialize song */ if (!xs_status.sidPlayer->plrInitSong(&xs_status)) { xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", tmpTune->sidFilename, xs_status.currSong); XS_MUTEX_UNLOCK(xs_status); goto xs_err_exit; } /* Open the audio output */ XSDEBUG("open audio output (%d, %d, %d)\n", xs_status.audioFormat, xs_status.audioFrequency, channels); if (!pb->output->open_audio(xs_status.audioFormat, xs_status.audioFrequency, channels)) { xs_error("Couldn't open audio output (fmt=%x, freq=%i, nchan=%i)!\n", xs_status.audioFormat, xs_status.audioFrequency, channels); XS_MUTEX_UNLOCK(xs_status); goto xs_err_exit; } /* Set song information for current subtune */ XSDEBUG("foobar #1\n"); xs_status.sidPlayer->plrUpdateSIDInfo(&xs_status); tmpTuple = tuple_new_from_filename(tmpTune->sidFilename); xs_get_song_tuple_info(tmpTuple, tmpTune, xs_status.currSong); xs_status.stop_flag = FALSE; XS_MUTEX_UNLOCK(xs_status); pb->set_tuple(pb, tmpTuple); pb->set_params (pb, -1, xs_status.audioFrequency, channels); pb->set_pb_ready(pb); XSDEBUG("playing\n"); while (1) { XS_MUTEX_LOCK (xs_status); if (xs_status.stop_flag) { XS_MUTEX_UNLOCK (xs_status); break; } XS_MUTEX_UNLOCK (xs_status); /* Render audio data */ if (xs_status.oversampleEnable) { /* Perform oversampled rendering */ bufRemaining = xs_status.sidPlayer->plrFillBuffer( &xs_status, oversampleBuffer, (audioBufSize * xs_status.oversampleFactor)); bufRemaining /= xs_status.oversampleFactor; /* Execute rate-conversion with filtering */ if (xs_filter_rateconv(audioBuffer, oversampleBuffer, xs_status.audioFormat, xs_status.oversampleFactor, bufRemaining) < 0) { xs_error("Oversampling rate-conversion pass failed.\n"); goto xs_err_exit; } } else { bufRemaining = xs_status.sidPlayer->plrFillBuffer( &xs_status, audioBuffer, audioBufSize); } pb->output->write_audio (audioBuffer, bufRemaining); /* Check if we have played enough */ if (xs_cfg.playMaxTimeEnable) { if (xs_cfg.playMaxTimeUnknown) { if (tmpLength < 0 && pb->output->written_time() >= xs_cfg.playMaxTime * 1000) break; } else { if (pb->output->written_time() >= xs_cfg.playMaxTime * 1000) break; } } if (tmpLength >= 0) { if (pb->output->written_time() >= tmpLength * 1000) break; } } DONE: XSDEBUG("out of playing loop\n"); g_free(audioBuffer); g_free(oversampleBuffer); /* Set playing status to false (stopped), thus when * XMMS next calls xs_get_time(), it can return appropriate * value "not playing" status and XMMS knows to move to * next entry in the playlist .. or whatever it wishes. */ XS_MUTEX_LOCK(xs_status); xs_status.stop_flag = TRUE; /* Free tune information */ xs_status.sidPlayer->plrDeleteSID(&xs_status); xs_tuneinfo_free(xs_status.tuneInfo); xs_status.tuneInfo = NULL; XS_MUTEX_UNLOCK(xs_status); /* Exit the playing thread */ XSDEBUG("exiting thread, bye.\n"); return ! error; xs_err_exit: error = TRUE; goto DONE; }
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; }
/* * Start playing the given file */ bool_t xs_play_file(const char *filename, VFSFile *file) { xs_tuneinfo_t *tmpTune; int audioBufSize, bufRemaining, tmpLength, subTune = -1; char *audioBuffer = NULL, *oversampleBuffer = NULL; Tuple *tmpTuple; uri_parse (filename, NULL, NULL, NULL, & subTune); /* Get tune information */ pthread_mutex_lock(&xs_status_mutex); if (! (xs_status.tuneInfo = xs_sidplayfp_getinfo (filename))) { pthread_mutex_unlock(&xs_status_mutex); return FALSE; } /* Initialize the tune */ if (! xs_sidplayfp_load (& xs_status, filename)) { pthread_mutex_unlock(&xs_status_mutex); xs_tuneinfo_free(xs_status.tuneInfo); xs_status.tuneInfo = NULL; return FALSE; } bool_t error = FALSE; /* Set general status information */ tmpTune = xs_status.tuneInfo; if (subTune < 1 || subTune > xs_status.tuneInfo->nsubTunes) xs_status.currSong = xs_status.tuneInfo->startTune; else xs_status.currSong = subTune; int channels = xs_status.audioChannels; /* Allocate audio buffer */ audioBufSize = xs_status.audioFrequency * channels * FMT_SIZEOF (FMT_S16_NE); if (audioBufSize < 512) audioBufSize = 512; audioBuffer = (char *) malloc(audioBufSize); if (audioBuffer == NULL) { xs_error("Couldn't allocate memory for audio data buffer!\n"); pthread_mutex_unlock(&xs_status_mutex); goto xs_err_exit; } /* Check minimum playtime */ tmpLength = tmpTune->subTunes[xs_status.currSong - 1].tuneLength; if (xs_cfg.playMinTimeEnable && (tmpLength >= 0)) { if (tmpLength < xs_cfg.playMinTime) tmpLength = xs_cfg.playMinTime; } /* Initialize song */ if (!xs_sidplayfp_initsong(&xs_status)) { xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", tmpTune->sidFilename, xs_status.currSong); pthread_mutex_unlock(&xs_status_mutex); goto xs_err_exit; } /* Open the audio output */ if (!aud_input_open_audio(FMT_S16_NE, xs_status.audioFrequency, channels)) { xs_error("Couldn't open audio output (fmt=%x, freq=%i, nchan=%i)!\n", FMT_S16_NE, xs_status.audioFrequency, channels); pthread_mutex_unlock(&xs_status_mutex); goto xs_err_exit; } /* Set song information for current subtune */ xs_sidplayfp_updateinfo(&xs_status); tmpTuple = tuple_new_from_filename(tmpTune->sidFilename); xs_get_song_tuple_info(tmpTuple, tmpTune, xs_status.currSong); pthread_mutex_unlock(&xs_status_mutex); aud_input_set_tuple(tmpTuple); while (! aud_input_check_stop ()) { bufRemaining = xs_sidplayfp_fillbuffer(&xs_status, audioBuffer, audioBufSize); aud_input_write_audio (audioBuffer, bufRemaining); /* Check if we have played enough */ if (xs_cfg.playMaxTimeEnable) { if (xs_cfg.playMaxTimeUnknown) { if (tmpLength < 0 && aud_input_written_time() >= xs_cfg.playMaxTime * 1000) break; } else { if (aud_input_written_time() >= xs_cfg.playMaxTime * 1000) break; } } if (tmpLength >= 0) { if (aud_input_written_time() >= tmpLength * 1000) break; } } DONE: free(audioBuffer); free(oversampleBuffer); /* Set playing status to false (stopped), thus when * XMMS next calls xs_get_time(), it can return appropriate * value "not playing" status and XMMS knows to move to * next entry in the playlist .. or whatever it wishes. */ pthread_mutex_lock(&xs_status_mutex); /* Free tune information */ xs_sidplayfp_delete(&xs_status); xs_tuneinfo_free(xs_status.tuneInfo); xs_status.tuneInfo = NULL; pthread_mutex_unlock(&xs_status_mutex); /* Exit the playing thread */ return ! error; xs_err_exit: error = TRUE; goto DONE; }
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; }
/* 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; }