static gboolean xmms_icymetaint_init (xmms_xform_t *xform) { xmms_icymetaint_data_t *data; gint32 meta_offset; gboolean res; g_return_val_if_fail (xform, FALSE); res = xmms_xform_auxdata_get_int (xform, "meta_offset", &meta_offset); g_return_val_if_fail (res, FALSE); XMMS_DBG ("meta_offset = %d", meta_offset); data = g_new0 (xmms_icymetaint_data_t, 1); data->metabuffer = g_malloc (256 * 16); data->meta_offset = meta_offset; xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/octet-stream", XMMS_STREAM_TYPE_END); xmms_xform_private_data_set (xform, data); return TRUE; }
static gboolean xmms_normalize_init (xmms_xform_t *xform) { xmms_config_property_t *cfgv; xmms_normalize_data_t *data; int i; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_normalize_data_t, 1); for (i = 0; i < G_N_ELEMENTS (config_params); i++) { cfgv = xmms_xform_config_lookup (xform, config_params[i].key); xmms_config_property_callback_set (cfgv, xmms_normalize_config_changed, data); xmms_normalize_config_changed (XMMS_OBJECT (cfgv), NULL, data); } xmms_xform_outdata_type_copy (xform); data->dirty = FALSE; data->compress = compress_new (data->use_anticlip, data->target, data->max_gain, data->smooth, data->buckets); xmms_xform_private_data_set (xform, data); return TRUE; }
static gboolean xmms_converter_plugin_init (xmms_xform_t *xform) { xmms_conv_xform_data_t *data; xmms_sample_converter_t *conv; xmms_stream_type_t *intype; xmms_stream_type_t *to; const GList *goal_hints; intype = xmms_xform_intype_get (xform); goal_hints = xmms_xform_goal_hints_get (xform); to = xmms_stream_type_coerce (intype, goal_hints); if (!to) { return FALSE; } conv = xmms_sample_converter_init (intype, to); if (!conv) { return FALSE; } xmms_xform_outdata_type_set (xform, to); xmms_object_unref (to); data = g_new0 (xmms_conv_xform_data_t, 1); data->conv = conv; xmms_xform_private_data_set (xform, data); return TRUE; }
static gboolean xmms_ringbuf_plugin_init (xmms_xform_t *xform) { xmms_config_property_t *config; xmms_ringbuf_priv_t *priv; gint buffer_size; priv = g_new0 (xmms_ringbuf_priv_t, 1); xmms_xform_private_data_set (xform, priv); config = xmms_xform_config_lookup (xform, "buffersize"); buffer_size = xmms_config_property_get_int (config); g_cond_init (&priv->state_cond); g_mutex_init (&priv->state_lock); g_mutex_init (&priv->buffer_lock); priv->state = STATE_WANT_BUFFER; priv->buffer = xmms_ringbuf_new (MAX (4096, buffer_size)); priv->thread = g_thread_new ("x2 ringbuf", xmms_ringbuf_xform_thread, xform); xmms_xform_outdata_type_copy (xform); return TRUE; }
static gboolean xmms_vocoder_init (xmms_xform_t *xform) { xmms_vocoder_data_t *priv; xmms_config_property_t *config; g_return_val_if_fail (xform, FALSE); priv = g_new0 (xmms_vocoder_data_t, 1); priv->winsize = 2048; priv->channels = xmms_xform_indata_get_int (xform, XMMS_STREAM_TYPE_FMT_CHANNELS); priv->bufsize = priv->winsize * priv->channels; priv->iobuf = g_malloc (priv->bufsize * sizeof (gint16)); priv->procbuf = g_malloc (priv->bufsize * sizeof (pvocoder_sample_t)); priv->resbuf = g_malloc (priv->bufsize * sizeof (gfloat)); priv->outbuf = g_string_new (NULL); priv->pvoc = pvocoder_init (priv->winsize, priv->channels); g_return_val_if_fail (priv->pvoc, FALSE); priv->resampler = src_new (SRC_LINEAR, priv->channels, NULL); g_return_val_if_fail (priv->resampler, FALSE); xmms_xform_private_data_set (xform, priv); config = xmms_xform_config_lookup (xform, "enabled"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_vocoder_config_changed, priv); priv->enabled = !!xmms_config_property_get_int (config); config = xmms_xform_config_lookup (xform, "speed"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_vocoder_config_changed, priv); priv->speed = (gfloat) xmms_config_property_get_int (config) / 100.0; config = xmms_xform_config_lookup (xform, "pitch"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_vocoder_config_changed, priv); priv->pitch = 100.0 / (gfloat) xmms_config_property_get_int (config); config = xmms_xform_config_lookup (xform, "attack_detection"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_vocoder_config_changed, priv); priv->attack_detection = !!xmms_config_property_get_int (config); pvocoder_set_scale (priv->pvoc, priv->speed * priv->pitch); pvocoder_set_attack_detection (priv->pvoc, priv->attack_detection); priv->resdata.data_in = NULL; priv->resdata.input_frames = 0; priv->resdata.data_out = priv->resbuf; priv->resdata.output_frames = priv->winsize; priv->resdata.src_ratio = priv->pitch; priv->resdata.end_of_input = 0; xmms_xform_outdata_type_copy (xform); return TRUE; }
static gboolean xmms_mpc_init (xmms_xform_t *xform) { xmms_mpc_data_t *data; xmms_error_t error; data = g_new0 (xmms_mpc_data_t, 1); xmms_xform_private_data_set (xform, data); if (!xmms_apetag_read (xform)) { XMMS_DBG ("Failed to read APEv2 tag"); } /* Reset to start after reading the tags */ xmms_error_reset (&error); xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_SET, &error); data->buffer = g_string_new (NULL); data->reader.read = xmms_mpc_callback_read; data->reader.seek = xmms_mpc_callback_seek; data->reader.tell = xmms_mpc_callback_tell; data->reader.canseek = xmms_mpc_callback_canseek; data->reader.get_size = xmms_mpc_callback_get_size; data->reader.data = xform; #ifdef HAVE_MPCDEC_OLD mpc_streaminfo_init (&data->info); if (mpc_streaminfo_read (&data->info, &data->reader) != ERROR_CODE_OK) return FALSE; mpc_decoder_setup (&data->decoder, &data->reader); if (mpc_decoder_initialize (&data->decoder, &data->info) == FALSE) return FALSE; #else data->demux = mpc_demux_init (&data->reader); if (!data->demux) return FALSE; mpc_demux_get_info (data->demux, &data->info); #endif xmms_mpc_cache_streaminfo (xform); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_FLOAT, XMMS_STREAM_TYPE_FMT_CHANNELS, data->info.channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->info.sample_freq, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_id3v2_init (xmms_xform_t *xform) { xmms_id3v2_data_t *data; xmms_id3v2_header_t head; xmms_error_t err; guchar hbuf[20]; gint filesize; guchar *buf; gint res; const gchar *metakey; xmms_error_reset (&err); if (xmms_xform_read (xform, hbuf, 10, &err) != 10) { XMMS_DBG ("Couldn't read id3v2 header..."); return FALSE; } data = g_new0 (xmms_id3v2_data_t, 1); xmms_xform_private_data_set (xform, data); if (!xmms_id3v2_is_header (hbuf, &head)) { XMMS_DBG ("Couldn't parse id3v2 header!?"); return FALSE; } /* Total data length is the length of header data plus header bytes */ data->len = head.len + 10; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; xmms_xform_metadata_set_int (xform, metakey, filesize - head.len); } buf = g_malloc (head.len); res = xmms_xform_read (xform, buf, head.len, &err); if (res != head.len) { XMMS_DBG ("Couldn't read id3v2 %d bytes of id3-data data (%d)", head.len, res); return FALSE; } xmms_id3v2_parse (xform, buf, &head); g_free (buf); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/octet-stream", XMMS_STREAM_TYPE_END); return TRUE; }
/* * Member functions */ static gboolean xmms_samba_init (xmms_xform_t *xform) { xmms_samba_data_t *data; const gchar *url; const gchar *metakey; struct stat st; gint fd, err; g_return_val_if_fail (xform, FALSE); url = xmms_xform_indata_get_str (xform, XMMS_STREAM_TYPE_URL); g_return_val_if_fail (url, FALSE); G_LOCK (mutex); err = smbc_stat (url, &st); G_UNLOCK (mutex); if (err < 0) { xmms_log_error ("%s", strerror (errno)); return FALSE; } if (!S_ISREG (st.st_mode)) { xmms_log_error ("%s is not a regular file.", url); return FALSE; } G_LOCK (mutex); fd = smbc_open (url, O_RDONLY | O_NONBLOCK, 0); G_UNLOCK (mutex); if (fd == -1) { xmms_log_error ("%s", strerror (errno)); return FALSE; } data = g_new0 (xmms_samba_data_t, 1); data->fd = fd; xmms_xform_private_data_set (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/octet-stream", XMMS_STREAM_TYPE_END); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; xmms_xform_metadata_set_int (xform, metakey, st.st_size); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_LMOD; xmms_xform_metadata_set_int (xform, metakey, st.st_mtime); return TRUE; }
static gboolean xmms_mpc_init (xmms_xform_t *xform) { xmms_mpc_data_t *data; data = g_new0 (xmms_mpc_data_t, 1); xmms_xform_private_data_set (xform, data); xmms_mpc_collect_metadata (xform); data->buffer = g_string_new (NULL); data->reader.read = xmms_mpc_callback_read; data->reader.seek = xmms_mpc_callback_seek; data->reader.tell = xmms_mpc_callback_tell; data->reader.canseek = xmms_mpc_callback_canseek; data->reader.get_size = xmms_mpc_callback_get_size; data->reader.data = xform; #ifdef HAVE_MPCDEC_OLD mpc_streaminfo_init (&data->info); if (mpc_streaminfo_read (&data->info, &data->reader) != ERROR_CODE_OK) return FALSE; mpc_decoder_setup (&data->decoder, &data->reader); if (mpc_decoder_initialize (&data->decoder, &data->info) == FALSE) return FALSE; #else data->demux = mpc_demux_init (&data->reader); if (!data->demux) return FALSE; mpc_demux_get_info (data->demux, &data->info); #endif xmms_mpc_cache_streaminfo (xform); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_FLOAT, XMMS_STREAM_TYPE_FMT_CHANNELS, data->info.channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->info.sample_freq, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_asf_init (xmms_xform_t *xform) { xmms_asf_data_t *data; asf_iostream_t stream; gint ret; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_asf_data_t, 1); stream.read = xmms_asf_read_callback; stream.write = NULL; stream.seek = xmms_asf_seek_callback; stream.opaque = xform; data->file = asf_open_cb (&stream); if (!data->file) { g_free (data); return FALSE; } data->packet = asf_packet_create (); data->outbuf = g_string_new (NULL); xmms_xform_private_data_set (xform, data); ret = asf_init (data->file); if (ret < 0) { XMMS_DBG ("ASF parser failed to init with error %d", ret); asf_packet_destroy (data->packet); asf_close (data->file); return FALSE; } data->track = xmms_asf_get_track (xform, data->file); if (data->track < 0) { XMMS_DBG ("No audio track found"); asf_packet_destroy (data->packet); asf_close (data->file); return FALSE; } xmms_asf_get_mediainfo (xform); XMMS_DBG ("ASF demuxer inited successfully!"); return TRUE; }
static gboolean xmms_sndfile_init (xmms_xform_t *xform) { xmms_sndfile_data_t *data; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_sndfile_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); data->sfvirtual.get_filelen = &xmms_sf_virtual_get_filelen; data->sfvirtual.seek = &xmms_sf_virtual_seek; data->sfvirtual.read = &xmms_sf_virtual_read; data->sfvirtual.write = &xmms_sf_virtual_write; data->sfvirtual.tell = &xmms_sf_virtual_tell; data->sndfile = sf_open_virtual (&data->sfvirtual, SFM_READ, &data->sf_info, xform); if (data->sndfile == NULL) { char errstr[1024]; sf_error_str (NULL, errstr, sizeof (errstr)); xmms_log_error ("libsndfile: sf_open_virtual failed with \"%s\".", errstr); g_free (data); return FALSE; } xmms_sndfile_get_media_info (xform); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S32, XMMS_STREAM_TYPE_FMT_CHANNELS, data->sf_info.channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->sf_info.samplerate, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_ofa_init (xmms_xform_t *xform) { xmms_ofa_data_t *data; xmms_medialib_entry_t entry; char *fp; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_ofa_data_t, 1); g_return_val_if_fail (data, FALSE); data->thread = g_thread_new ("x2 ofa calc", xmms_ofa_thread, data); if (!data->thread) { g_free (data); return FALSE; } g_mutex_init (&data->mutex); g_cond_init (&data->cond); data->bytes_to_read = 44100 * 135 * 4; data->buf = g_malloc (data->bytes_to_read); entry = xmms_xform_entry_get (xform); /* TODO: #2482 fp = xmms_medialib_entry_property_get_str (entry, "ofa_fingerprint"); */ fp = NULL; if (fp) { XMMS_DBG ("Entry already has ofa_fingerprint, not recalculating"); /* keep it! */ xmms_xform_metadata_set_str (xform, "ofa_fingerprint", fp); g_free (fp); } else { data->run_ofa = TRUE; } xmms_xform_private_data_set (xform, data); xmms_xform_outdata_type_copy (xform); return TRUE; }
static gboolean xmms_nulstripper_init (xmms_xform_t *xform) { xmms_nulstripper_data_t *data; guint o; o = find_offset (xform); if (!o) { return FALSE; } data = g_new (xmms_nulstripper_data_t, 1); data->offset = o; xmms_xform_private_data_set (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/octet-stream", XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_daap_init (xmms_xform_t *xform) { gint dbid; GSList *dbid_list = NULL; xmms_daap_data_t *data; xmms_daap_login_data_t *login_data; xmms_error_t err; const gchar *url; const gchar *metakey; gchar *command, *hash; guint filesize; g_return_val_if_fail (xform, FALSE); url = xmms_xform_indata_get_str (xform, XMMS_STREAM_TYPE_URL); g_return_val_if_fail (url, FALSE); data = g_new0 (xmms_daap_data_t, 1); xmms_error_reset (&err); if (!get_data_from_url (url, &(data->host), &(data->port), &command, &err)) { goto init_error; } hash = g_strdup_printf ("%s:%u", data->host, data->port); login_data = g_hash_table_lookup (login_sessions, hash); if (!login_data) { XMMS_DBG ("creating login data for %s", hash); login_data = g_new0 (xmms_daap_login_data_t, 1); login_data->request_id = 1; login_data->logged_in = TRUE; login_data->session_id = daap_command_login (data->host, data->port, login_data->request_id, &err); if (xmms_error_iserror (&err)) { g_free (login_data); goto init_error; } g_hash_table_insert (login_sessions, hash, login_data); } login_data->revision_id = daap_command_update (data->host, data->port, login_data->session_id, login_data->request_id); dbid_list = daap_command_db_list (data->host, data->port, login_data->session_id, login_data->revision_id, login_data->request_id); if (!dbid_list) { goto init_error; } /* XXX: see XXX in the browse function above */ dbid = ((cc_item_record_t *) dbid_list->data)->dbid; /* want to request a stream, but don't read the data yet */ data->conn = daap_command_init_stream (data->host, data->port, login_data->session_id, login_data->revision_id, login_data->request_id, dbid, command, &filesize); if (! data->conn) { goto init_error; } login_data->request_id++; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; xmms_xform_metadata_set_int (xform, metakey, filesize); xmms_xform_private_data_set (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/octet-stream", XMMS_STREAM_TYPE_END); g_slist_foreach (dbid_list, (GFunc) cc_item_record_free, NULL); g_slist_free (dbid_list); g_free (command); return TRUE; init_error: if (data) { if (data->host) g_free (data->host); g_free (data); } return FALSE; }
static gboolean xmms_gme_init (xmms_xform_t *xform) { xmms_gme_data_t *data; gme_err_t init_error; GString *file_contents; /* The raw data from the file. */ gme_info_t *metadata = NULL; xmms_config_property_t *val; int loops; int maxlength; const char *subtune_str; int subtune = 0; long fadelen = -1; int samplerate; double stereodepth; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_gme_data_t, 1); xmms_xform_private_data_set (xform, data); val = xmms_xform_config_lookup (xform, "samplerate"); samplerate = xmms_config_property_get_int (val); if (samplerate < 1) samplerate = GME_DEFAULT_SAMPLE_RATE; data->samplerate = samplerate; xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", /* PCM samples */ XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, /* 16-bit signed */ XMMS_STREAM_TYPE_FMT_CHANNELS, 2, /* stereo */ XMMS_STREAM_TYPE_FMT_SAMPLERATE, samplerate, XMMS_STREAM_TYPE_END); file_contents = g_string_new (""); for (;;) { xmms_error_t error; gchar buf[4096]; gint ret; ret = xmms_xform_read (xform, buf, sizeof (buf), &error); if (ret == -1) { XMMS_DBG ("Error reading emulated music data"); return FALSE; } if (ret == 0) { break; } g_string_append_len (file_contents, buf, ret); } init_error = gme_open_data (file_contents->str, file_contents->len, &data->emu, samplerate); g_string_free (file_contents, TRUE); if (init_error) { XMMS_DBG ("gme_open_data returned an error: %s", init_error); return FALSE; } if (xmms_xform_metadata_get_str (xform, "subtune", &subtune_str)) { subtune = strtol (subtune_str, NULL, 10); XMMS_DBG ("Setting subtune to %d", subtune); if ((subtune < 0 || subtune > gme_track_count (data->emu))) { XMMS_DBG ("Invalid subtune index"); return FALSE; } } else { xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SUBTUNES, gme_track_count (data->emu)); } /* * Get metadata here */ init_error = gme_track_info (data->emu, &metadata, subtune); if (init_error) { XMMS_DBG ("Couldn't get GME track info: %s", init_error); init_error = ""; } else { xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE, metadata->song); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST, metadata->author); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM, metadata->game); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT, metadata->comment); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR, metadata->copyright); xmms_xform_metadata_set_str (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE, metadata->system); /* I mapped genre to the system type */ val = xmms_xform_config_lookup (xform, "loops"); loops = xmms_config_property_get_int (val); XMMS_DBG ("intro_length = %d, loops = %d, loop_length = %d", metadata->intro_length, loops, metadata->loop_length); if (metadata->intro_length > 0) { if ((loops > 0) && (metadata->loop_length > 0)) { fadelen = metadata->intro_length + loops * metadata->loop_length; XMMS_DBG ("fadelen now = %ld", fadelen); } else { fadelen = metadata->length; XMMS_DBG ("fadelen now = %ld", fadelen); } } } val = xmms_xform_config_lookup (xform, "maxlength"); maxlength = xmms_config_property_get_int (val); XMMS_DBG ("maxlength = %d seconds", maxlength); if (maxlength > 0 && (fadelen < 0 || (maxlength * 1000L < fadelen))) { fadelen = maxlength * 1000L; XMMS_DBG ("fadelen now = %ld", fadelen); } XMMS_DBG ("gme.fadelen = %ld", fadelen); val = xmms_xform_config_lookup (xform, "stereodepth"); stereodepth = xmms_config_property_get_float (val); if (stereodepth >= 0.0 && stereodepth <= 1.0) { XMMS_DBG ("Setting stereo depth to %f.", stereodepth); gme_set_stereo_depth (data->emu, stereodepth); } else { XMMS_DBG ("gme.stereodepth = %f out of range 0.0 - 1.0; not setting.", stereodepth); } init_error = gme_start_track (data->emu, subtune); if (init_error) { XMMS_DBG ("gme_start_track returned an error: %s", init_error); gme_free_info (metadata); return FALSE; } if (fadelen > 0) { XMMS_DBG ("Setting song length and fade length..."); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, fadelen); gme_set_fade (data->emu, fadelen); } gme_free_info (metadata); return TRUE; }
static gboolean xmms_faad_init (xmms_xform_t *xform) { xmms_faad_data_t *data; xmms_error_t error; NeAACDecConfigurationPtr config; gint bytes_read; gulong samplerate; guchar channels; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_faad_data_t, 1); data->outbuf = g_string_new (NULL); data->buffer_size = FAAD_BUFFER_SIZE; xmms_xform_private_data_set (xform, data); data->decoder = NeAACDecOpen (); config = NeAACDecGetCurrentConfiguration (data->decoder); config->defObjectType = LC; config->defSampleRate = 44100; config->outputFormat = FAAD_FMT_16BIT; config->downMatrix = 0; config->dontUpSampleImplicitSBR = 0; NeAACDecSetConfiguration (data->decoder, config); switch (config->outputFormat) { case FAAD_FMT_16BIT: data->sampleformat = XMMS_SAMPLE_FORMAT_S16; break; case FAAD_FMT_24BIT: /* we don't have 24-bit format to use in xmms2 */ data->sampleformat = XMMS_SAMPLE_FORMAT_S32; break; case FAAD_FMT_32BIT: data->sampleformat = XMMS_SAMPLE_FORMAT_S32; break; case FAAD_FMT_FLOAT: data->sampleformat = XMMS_SAMPLE_FORMAT_FLOAT; break; case FAAD_FMT_DOUBLE: data->sampleformat = XMMS_SAMPLE_FORMAT_DOUBLE; break; } while (data->buffer_length < 8) { xmms_error_reset (&error); bytes_read = xmms_xform_read (xform, (gchar *) data->buffer + data->buffer_length, data->buffer_size - data->buffer_length, &error); data->buffer_length += bytes_read; if (bytes_read < 0) { xmms_log_error ("Error while trying to read data on init"); goto err; } else if (bytes_read == 0) { XMMS_DBG ("Not enough bytes to check the AAC header"); goto err; } } /* which type of file are we dealing with? */ data->filetype = FAAD_TYPE_UNKNOWN; if (xmms_xform_auxdata_has_val (xform, "decoder_config")) { data->filetype = FAAD_TYPE_MP4; } else if (!strncmp ((char *) data->buffer, "ADIF", 4)) { data->filetype = FAAD_TYPE_ADIF; } else { int i; /* ADTS mpeg file can be a stream and start in the middle of a * frame so we need to have extra loop check here */ for (i=0; i<data->buffer_length-1; i++) { if (data->buffer[i] == 0xff && (data->buffer[i+1]&0xf6) == 0xf0) { data->filetype = FAAD_TYPE_ADTS; g_memmove (data->buffer, data->buffer+i, data->buffer_length-i); data->buffer_length -= i; break; } } } if (data->filetype == FAAD_TYPE_ADTS || data->filetype == FAAD_TYPE_ADIF) { bytes_read = NeAACDecInit (data->decoder, data->buffer, data->buffer_length, &samplerate, &channels); } else if (data->filetype == FAAD_TYPE_MP4) { const guchar *tmpbuf; gsize tmpbuflen; guchar *copy; if (!xmms_xform_auxdata_get_bin (xform, "decoder_config", &tmpbuf, &tmpbuflen)) { XMMS_DBG ("AAC decoder config data found but it's wrong type! (something broken?)"); goto err; } copy = g_memdup (tmpbuf, tmpbuflen); bytes_read = NeAACDecInit2 (data->decoder, copy, tmpbuflen, &samplerate, &channels); g_free (copy); } if (bytes_read < 0) { XMMS_DBG ("Error initializing decoder library."); goto err; } /* Get mediainfo and skip the possible header */ xmms_faad_get_mediainfo (xform); g_memmove (data->buffer, data->buffer + bytes_read, data->buffer_length - bytes_read); data->buffer_length -= bytes_read; data->samplerate = samplerate; data->channels = channels; /* Because for HE AAC files some versions of libfaad return the wrong * samplerate in init, we have to do one read and let it decide the * real parameters. After changing sample parameters and format is * supported, this hack should be removed and handled in read instead. */ { gchar tmpbuf[1024]; xmms_error_reset (&error); bytes_read = xmms_faad_read (xform, tmpbuf, 1024, &error); if (bytes_read <= 0) { XMMS_DBG ("First read from faad decoder failed!"); return FALSE; } g_string_prepend_len (data->outbuf, tmpbuf, bytes_read); } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, data->sampleformat, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->samplerate, XMMS_STREAM_TYPE_END); XMMS_DBG ("AAC decoder inited successfully!"); return TRUE; err: g_string_free (data->outbuf, TRUE); g_free (data); return FALSE; }
static gboolean xmms_speex_init (xmms_xform_t *xform) { gint pe; xmms_config_property_t *val; xmms_speex_data_t *data; xmms_error_t error; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_speex_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); ogg_sync_init (&data->sync_state); speex_bits_init (&data->speex_bits); /* Find the speex header */ while (42) { gint ret; data->ogg_data = ogg_sync_buffer (&data->sync_state, 1024); ret = xmms_xform_read (xform, data->ogg_data, 1024, &error); ogg_sync_wrote (&data->sync_state, ret); if (ret <= 0) { return FALSE; } if (ogg_sync_pageout (&data->sync_state, &data->ogg_page) == 1) { break; } } ogg_stream_init (&data->stream_state, ogg_page_serialno (&data->ogg_page)); if (ogg_stream_pagein (&data->stream_state, &data->ogg_page) < 0) { return FALSE; } if (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) != 1) { return FALSE; } data->speexheader = speex_packet_to_header ((char *)data->ogg_packet.packet, data->ogg_packet.bytes); data->speex_state = speex_decoder_init (speex_mode_list[data->speexheader->mode]); val = xmms_xform_config_lookup (xform, "perceptual_enhancer"); pe = xmms_config_property_get_int (val); speex_decoder_ctl (data->speex_state, SPEEX_SET_ENH, &pe); ogg_sync_pageout (&data->sync_state, &data->ogg_page); ogg_stream_pagein (&data->stream_state, &data->ogg_page); ogg_stream_packetout (&data->stream_state, &data->ogg_packet); data->samples_buf = g_new (gint16, data->speexheader->frames_per_packet * data->speexheader->frame_size * data->speexheader->nb_channels); data->samples_start = data->samples_buf; data->samples_count = 0; xmms_speex_read_metadata (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->speexheader->nb_channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->speexheader->rate, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_wavpack_init (xmms_xform_t *xform) { xmms_wavpack_data_t *data; xmms_sample_format_t sample_format; gint samplerate; /* the maximum length of error really isn't defined... stupid */ gchar error[1024]; g_return_val_if_fail (xform, FALSE); if (!xmms_apetag_read (xform)) { XMMS_DBG ("Failed to read APEv2 tag"); } data = g_new0 (xmms_wavpack_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); data->reader.read_bytes = wavpack_read_bytes; data->reader.get_pos = wavpack_get_pos; data->reader.set_pos_abs = wavpack_set_pos_abs; data->reader.set_pos_rel = wavpack_set_pos_rel; data->reader.push_back_byte = wavpack_push_back_byte; data->reader.get_length = wavpack_get_length; data->reader.can_seek = wavpack_can_seek; data->ctx = WavpackOpenFileInputEx (&data->reader, xform, xform, error, OPEN_TAGS, 0); if (!data->ctx) { xmms_log_error ("Unable to open wavpack file: %s", error); xmms_xform_private_data_set (xform, NULL); xmms_wavpack_free_data (data); return FALSE; } data->channels = WavpackGetNumChannels (data->ctx); data->bits_per_sample = WavpackGetBitsPerSample (data->ctx); data->num_samples = WavpackGetNumSamples (data->ctx); samplerate = WavpackGetSampleRate (data->ctx); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, (int) (1000.0 * data->num_samples / samplerate)); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SAMPLERATE, samplerate); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE, (int) WavpackGetAverageBitrate (data->ctx, FALSE)); switch (data->bits_per_sample) { case 8: sample_format = XMMS_SAMPLE_FORMAT_S8; break; case 12: case 16: sample_format = XMMS_SAMPLE_FORMAT_S16; break; case 24: case 32: sample_format = XMMS_SAMPLE_FORMAT_S32; break; default: xmms_log_error ("Unsupported bits-per-sample in wavpack file: %d", data->bits_per_sample); xmms_xform_private_data_set (xform, NULL); xmms_wavpack_free_data (data); return FALSE; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, sample_format, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, samplerate, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_mpg123_init (xmms_xform_t *xform) { xmms_mpg123_data_t *data; const long *rates; size_t num_rates; int encoding; off_t length; int i, result; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mpg123_data_t, 1); xmms_xform_private_data_set (xform, data); /* Get the total size of this stream and store it for later */ if (xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE, &result)) { data->filesize = result; } mpg123_rates (&rates, &num_rates); data->param = mpg123_new_pars (&result); g_return_val_if_fail (data->param, FALSE); /* Create a quiet (stderr) decoder with auto choosen optimization. * Stuff set here should be tunable via plugin config properties! * You can also change some things during playback... */ mpg123_par (data->param, MPG123_ADD_FLAGS, MPG123_QUIET, 0); mpg123_par (data->param, MPG123_ADD_FLAGS, MPG123_GAPLESS, 0); /* choose: MPG123_RVA_OFF, MPG123_RVA_MIX, MPG123_RVA_ALBUM * xmms2 has its own ReplayGain plugin to handle the RVA field */ mpg123_par (data->param, MPG123_RVA, MPG123_RVA_OFF, 0); /* You could choose a decoder from the list provided by * mpg123_supported_decoders () and give that as second parameter. */ data->decoder = mpg123_parnew (data->param, NULL, &result); if (data->decoder == NULL) { xmms_log_error ("%s", mpg123_plain_strerror (result)); goto bad; } /* Prepare for buffer input feeding. */ result = mpg123_open_feed (data->decoder); if (result != MPG123_OK) { goto mpg123_bad; } /* Let's always decode to signed 16bit for a start. Any mpg123-supported sample rate is accepted. */ if (MPG123_OK != mpg123_format_none (data->decoder)) { goto mpg123_bad; } for (i = 0; i < num_rates; i++) { result = mpg123_format (data->decoder, rates[i], MPG123_MONO | MPG123_STEREO, MPG123_ENC_SIGNED_16); if (result != MPG123_OK) { goto mpg123_bad; } } /* Fetch ID3v1 data from the end of file if possible */ result = xmms_id3v1_get_tags (xform); if (result < 0) { xmms_log_error ("Seeking error when reading ID3v1 tags"); goto bad; } else if (data->filesize > result) { /* Reduce the size of tag data from the filesize */ data->filesize -= result; } /* Read data from input until decoded data is available from decoder */ do { /* Parse stream and get info. */ gint ret; xmms_error_t err; ret = xmms_xform_read (xform, data->buf, BUFSIZE, &err); if (ret < 0) { xmms_log_error ("Error when trying to find beginning of stream"); goto bad; } else if (ret == 0) { /* EOF reached before format was found, handled after loop */ break; } /* With zero output size nothing is actually outputted */ result = mpg123_decode (data->decoder, data->buf, (size_t) ret, NULL, 0, NULL); } while (result == MPG123_NEED_MORE); /* Keep feeding... */ if (result != MPG123_NEW_FORMAT) { xmms_log_error ("Unable to find beginning of stream (%s)!", result == MPG123_ERR ? mpg123_strerror (data->decoder) : "unexpected EOF"); goto bad; } result = mpg123_getformat (data->decoder, &data->samplerate, &data->channels, &encoding); if (result != MPG123_OK) { goto mpg123_bad; } /* Set the filesize so it can be used for duration estimation */ if (data->filesize > 0) { mpg123_set_filesize (data->decoder, data->filesize); } /* Get duration in samples, convert to ms and save to xmms2 */ length = mpg123_length (data->decoder); if (length > 0 && !xmms_xform_metadata_get_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, &i)) { length = (off_t) ((gfloat) length / data->samplerate * 1000); xmms_xform_metadata_set_int (xform, XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION, (gint) length); } XMMS_DBG ("mpg123: got stream with %li Hz %i channels, encoding %i", data->samplerate, data->channels, encoding); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, (gint) data->samplerate, XMMS_STREAM_TYPE_END); return TRUE; mpg123_bad: xmms_log_error ("mpg123 error: %s", mpg123_strerror (data->decoder)); bad: mpg123_delete (data->decoder); mpg123_delete_pars (data->param); g_free (data); return FALSE; }
static gboolean xmms_mad_init (xmms_xform_t *xform) { struct mad_frame frame; struct mad_stream stream; xmms_error_t err; guchar buf[40960]; xmms_mad_data_t *data; int len; const gchar *metakey; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mad_data_t, 1); mad_stream_init (&data->stream); mad_frame_init (&data->frame); mad_synth_init (&data->synth); xmms_xform_private_data_set (xform, data); data->buffer_length = 0; data->synthpos = 0x7fffffff; mad_stream_init (&stream); mad_frame_init (&frame); len = xmms_xform_peek (xform, buf, 40960, &err); mad_stream_buffer (&stream, buf, len); while (mad_frame_decode (&frame, &stream) == -1) { if (!MAD_RECOVERABLE (stream.error)) { XMMS_DBG ("couldn't decode %02x %02x %02x %02x",buf[0],buf[1],buf[2],buf[3]); mad_frame_finish (&frame); mad_stream_finish (&stream); return FALSE; } } data->channels = frame.header.mode == MAD_MODE_SINGLE_CHANNEL ? 1 : 2; data->samplerate = frame.header.samplerate; if (frame.header.flags & MAD_FLAG_PROTECTION) { XMMS_DBG ("Frame has protection enabled"); if (stream.anc_ptr.byte > stream.buffer + 2) { stream.anc_ptr.byte = stream.anc_ptr.byte - 2; } } data->samples_to_play = -1; data->xing = xmms_xing_parse (stream.anc_ptr); if (data->xing) { xmms_xing_lame_t *lame; XMMS_DBG ("File with Xing header!"); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_IS_VBR; xmms_xform_metadata_set_int (xform, metakey, 1); if (xmms_xing_has_flag (data->xing, XMMS_XING_FRAMES)) { guint duration; mad_timer_t timer; timer = frame.header.duration; mad_timer_multiply (&timer, xmms_xing_get_frames (data->xing)); duration = mad_timer_count (timer, MAD_UNITS_MILLISECONDS); XMMS_DBG ("XING duration %d", duration); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, duration); if (xmms_xing_has_flag (data->xing, XMMS_XING_BYTES) && duration) { guint tmp; tmp = xmms_xing_get_bytes (data->xing) * ((guint64)8000) / duration; XMMS_DBG ("XING bitrate %d", tmp); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, tmp); } } lame = xmms_xing_get_lame (data->xing); if (lame) { /* FIXME: add a check for ignore_lame_headers from the medialib */ data->frames_to_skip = 1; data->samples_to_skip = lame->start_delay; data->samples_to_play = ((guint64) xmms_xing_get_frames (data->xing) * 1152ULL) - lame->start_delay - lame->end_padding; XMMS_DBG ("Samples to skip in the beginning: %d, total: %" G_GINT64_FORMAT, data->samples_to_skip, data->samples_to_play); /* metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_ALBUM; xmms_xform_metadata_set_int (xform, metakey, lame->audiophile_gain); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_PEAK_TRACK; xmms_xform_metadata_set_int (xform, metakey, lame->peak_amplitude); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_GAIN_TRACK; xmms_xform_metadata_set_int (xform, metakey, lame->radio_gain); */ } } else { gint filesize; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, frame.header.bitrate); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; if (!xmms_xform_metadata_get_int (xform, metakey, &filesize)) { metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) { gint32 val; val = (gint32) (filesize * (gdouble) 8000.0 / frame.header.bitrate); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, val); } } } /* seeking needs bitrate */ data->bitrate = frame.header.bitrate; if (xmms_id3v1_get_tags (xform) < 0) { mad_stream_finish (&data->stream); mad_frame_finish (&data->frame); mad_synth_finish (&data->synth); if (data->xing) { xmms_xing_free (data->xing); } return FALSE; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->samplerate, XMMS_STREAM_TYPE_END); mad_frame_finish (&frame); mad_stream_finish (&stream); return TRUE; }
static gboolean xmms_gvfs_init (xmms_xform_t *xform) { xmms_gvfs_data_t *data; GFile *file; GFileInfo *info; GFileInputStream *handle; GError *error = NULL; const gchar *url; url = xmms_xform_indata_get_str (xform, XMMS_STREAM_TYPE_URL); g_return_val_if_fail (url, FALSE); /* This is an ugly hack to handle files with chars needing url encoding */ if (!g_ascii_strncasecmp (url, "file://", 7)) { file = g_file_new_for_path (url+7); } else { file = g_file_new_for_uri (url); } handle = g_file_read (file, NULL, &error); g_object_unref (file); if (!handle) { xmms_log_error ("Failed to upen url %s for reading: %s", url, error->message); return FALSE; } data = g_new (xmms_gvfs_data_t, 1); data->handle = G_INPUT_STREAM (handle); xmms_xform_private_data_set (xform, data); info = g_file_input_stream_query_info (handle, (char *)query_attributes, NULL, &error); if (!info) { xmms_log_info ("failed to query information for %s", url); } else { int i; for (i = 0; i < G_N_ELEMENTS (attr_map); i++) { if (!g_file_info_has_attribute (info, attr_map[i].gvfs)) { continue; } switch (attr_map[i].type) { case XMMSV_TYPE_STRING: { gchar *attr = g_file_info_get_attribute_as_string (info, attr_map[i].gvfs); xmms_xform_metadata_set_str (xform, attr_map[i].mlib, attr); g_free (attr); break; } case XMMSV_TYPE_INT32: { /* right now the xform metadata api only handles strings * and 32 bit ints. however the gvfs api returns uint64 for * the numeric attributes we're interested in and we just * pass that to the xform and pray that it doesn't overflow * as we know it's unsafe. */ gint64 attr = g_file_info_get_attribute_uint64 (info, attr_map[i].gvfs); xmms_xform_metadata_set_int (xform, attr_map[i].mlib, attr); break; } default: g_assert_not_reached (); } } g_object_unref (info); } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/octet-stream", XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_midsquash_init (xmms_xform_t *xform) { xmms_error_t error; xmms_midsquash_data_t *data; gulong track_len, len; gint32 ticks_per_quarter_note; const gchar *metakey; guchar buf[4096]; gint ret; guchar prev_event = 0; GArray *events = NULL; GArray *track_data = NULL; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_midsquash_data_t, 1); xmms_xform_private_data_set (xform, data); data->midi0_data = NULL; if (!xmms_xform_auxdata_get_int (xform, "tempo", &ticks_per_quarter_note)) { XMMS_DBG ("MIDI xform missing 'tempo' auxdata value"); goto error_cleanup; } xmms_xform_auxdata_set_int (xform, "tempo", ticks_per_quarter_note); /* Load all the tracks */ events = g_array_new(FALSE, FALSE, sizeof(xmms_midsquash_event_t)); track_data = g_array_new(FALSE, FALSE, sizeof(GString *)); while (xmms_xform_read (xform, buf, 4, &error) == 4) { track_len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; GString *t = g_string_sized_new(track_len); ret = xmms_xform_read (xform, t->str, track_len, &error); g_array_append_val(track_data, t); /* Run through the MIDI data in this track, and convert it to a list of * events in absolute ticks (instead of delta ticks.) */ gulong i = 0; gulong abs_ticks = 0; while (i < track_len) { abs_ticks += xmms_midisquash_read_midi_num(t->str, &i); xmms_midsquash_event_t event; gboolean ignore_event = FALSE; event.time = abs_ticks; event.offset = &t->str[i]; gulong i0 = i; /* Read MIDI event */ guchar midi_event = t->str[i]; if (!(midi_event & 0x80)) { /* This is a running-status byte */ midi_event = prev_event; event.running_status = prev_event; } else { if ((midi_event & 0xF0) != 0xF0) { /* Meta events (0xF0 through 0xFF) can appear in the middle of * running-status data without affecting the running status, so we * only update the 'last event' if this isn't a meta-event. */ prev_event = midi_event; } event.running_status = 0; i++; } switch (midi_event & 0xF0) { case 0x80: /* Note off (two bytes) */ i += 2; break; case 0x90: /* Note on (two bytes) */ i += 2; break; case 0xA0: /* Key pressure (two bytes) */ i += 2; break; case 0xB0: /* Controller change (two bytes) */ i += 2; break; case 0xC0: /* Instrument change (one byte) */ i += 1; break; case 0xD0: /* Channel pressure (one byte) */ i += 1; break; case 0xE0: /* Pitch bend (two bytes) */ i += 2; break; case 0xF0: { if (midi_event == 0xFF) { /* Meta-event */ if (t->str[i] == 0x2F) { /* This is an end-of-track event, so we need to ignore it * otherwise the song will end as soon as we encounter the end * of the shortest track (which could be quite early on.) */ ignore_event = TRUE; } i++; /* event type */ } /* else sysex */ len = xmms_midisquash_read_midi_num(t->str, &i); i += len; break; } default: XMMS_DBG ("Corrupted MIDI file (invalid event 0x%02X)", midi_event); goto error_cleanup; } event.length = i - i0; if (!ignore_event) g_array_append_val(events, event); } /* end loop: run through all the track's events */ } /* Now that all the events have been read in, in absolute time, sorting them * will put them all in playable order. */ g_array_sort(events, xmms_midsquash_sort_events); /* Now copy all the sorted events into a big array, which will be used as * the output data. */ data->midi0_data = g_string_new(""); gulong last_time = 0; guint64 playtime_us = 0; gulong us_per_quarter_note = 500000; gulong i, j; guchar val; for (i = 0; i < events->len; i++) { xmms_midsquash_event_t *e; e = &g_array_index(events, xmms_midsquash_event_t, i); /* Calculate the delta time and write it out in MIDI style */ gulong delta_ticks = e->time - last_time; if (delta_ticks & (0x7F << 21)) { val = ((delta_ticks >> 21) & 0x7F) | 0x80; g_string_append_len(data->midi0_data, (gchar *)&val, 1); } if (delta_ticks & ((0x7F << 21) | (0x7F << 14))) { val = ((delta_ticks >> 14) & 0x7F) | 0x80; g_string_append_len(data->midi0_data, (gchar *)&val, 1); }
static gboolean xmms_flac_init (xmms_xform_t *xform) { xmms_flac_data_t *data; xmms_sample_format_t sample_fmt; FLAC__bool retval; #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 FLAC__StreamDecoderState init_status; #else FLAC__StreamDecoderInitStatus init_status; #endif gint filesize; const gchar *metakey; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_flac_data_t, 1); xmms_xform_private_data_set (xform, data); data->flacdecoder = FLAC__stream_decoder_new (); /* we don't need to explicitly tell the decoder to respond to * FLAC__METADATA_TYPE_STREAMINFO here, it always does. */ #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 FLAC__seekable_stream_decoder_set_metadata_respond (data->flacdecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__seekable_stream_decoder_set_eof_callback (data->flacdecoder, flac_callback_eof); FLAC__seekable_stream_decoder_set_read_callback (data->flacdecoder, flac_callback_read); FLAC__seekable_stream_decoder_set_seek_callback (data->flacdecoder, flac_callback_seek); FLAC__seekable_stream_decoder_set_tell_callback (data->flacdecoder, flac_callback_tell); FLAC__seekable_stream_decoder_set_write_callback (data->flacdecoder, flac_callback_write); FLAC__seekable_stream_decoder_set_error_callback (data->flacdecoder, flac_callback_error); FLAC__seekable_stream_decoder_set_length_callback (data->flacdecoder, flac_callback_length); FLAC__seekable_stream_decoder_set_metadata_callback (data->flacdecoder, flac_callback_metadata); FLAC__seekable_stream_decoder_set_client_data (data->flacdecoder, xform); init_status = FLAC__seekable_stream_decoder_init (data->flacdecoder); if (init_status != FLAC__SEEKABLE_STREAM_DECODER_OK) { const gchar *errmsg = FLAC__seekable_stream_decoder_get_resolved_state_string (data->flacdecoder); XMMS_DBG ("FLAC init failed: %s", errmsg); goto err; } #else FLAC__stream_decoder_set_metadata_respond (data->flacdecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); FLAC__stream_decoder_set_metadata_respond (data->flacdecoder, FLAC__METADATA_TYPE_PICTURE); init_status = FLAC__stream_decoder_init_stream (data->flacdecoder, flac_callback_read, flac_callback_seek, flac_callback_tell, flac_callback_length, flac_callback_eof, flac_callback_write, flac_callback_metadata, flac_callback_error, xform); if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { XMMS_DBG ("FLAC init failed: %s", FLAC__stream_decoder_get_resolved_state_string (data->flacdecoder)); goto err; } #endif retval = FLAC__stream_decoder_process_until_end_of_metadata (data->flacdecoder); if (!retval) goto err; if (data->vorbiscomment) { handle_comments (xform, data); } metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, (gint) data->bit_rate); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) { gint32 val = (gint32) data->total_samples / data->sample_rate * 1000; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, val); } if (data->bits_per_sample == 8) { sample_fmt = XMMS_SAMPLE_FORMAT_S8; } else if (data->bits_per_sample == 16) { sample_fmt = XMMS_SAMPLE_FORMAT_S16; } else if (data->bits_per_sample == 24) { sample_fmt = XMMS_SAMPLE_FORMAT_S32; } else if (data->bits_per_sample == 32) { sample_fmt = XMMS_SAMPLE_FORMAT_S32; } else { goto err; } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, sample_fmt, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, data->sample_rate, XMMS_STREAM_TYPE_END); data->buffer = g_string_new (NULL); return TRUE; err: FLAC__stream_decoder_finish (data->flacdecoder); FLAC__stream_decoder_delete (data->flacdecoder); g_free (data); xmms_xform_private_data_set (xform, NULL); return FALSE; }
static gboolean xmms_eq_init (xmms_xform_t *xform) { xmms_equalizer_data_t *priv; xmms_config_property_t *config; gint i, j, srate; gfloat gain; g_return_val_if_fail (xform, FALSE); priv = g_new0 (xmms_equalizer_data_t, 1); g_return_val_if_fail (priv, FALSE); xmms_xform_private_data_set (xform, priv); config = xmms_xform_config_lookup (xform, "enabled"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_eq_config_changed, priv); priv->enabled = !!xmms_config_property_get_int (config); config = xmms_xform_config_lookup (xform, "bands"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_eq_config_changed, priv); priv->bands = xmms_config_property_get_int (config); config = xmms_xform_config_lookup (xform, "extra_filtering"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_eq_config_changed, priv); priv->extra_filtering = xmms_config_property_get_int (config); config = xmms_xform_config_lookup (xform, "use_legacy"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_eq_config_changed, priv); priv->use_legacy = xmms_config_property_get_int (config); config = xmms_xform_config_lookup (xform, "preamp"); g_return_val_if_fail (config, FALSE); xmms_config_property_callback_set (config, xmms_eq_gain_changed, priv); gain = xmms_config_property_get_float (config); for (i=0; i<EQ_CHANNELS; i++) { set_preamp (i, xmms_eq_gain_scale (gain, TRUE)); } for (i=0; i<EQ_BANDS_LEGACY; i++) { gchar buf[16]; g_snprintf (buf, sizeof (buf), "legacy%d", i); config = xmms_xform_config_lookup (xform, buf); g_return_val_if_fail (config, FALSE); priv->legacy[i] = config; xmms_config_property_callback_set (config, xmms_eq_gain_changed, priv); gain = xmms_config_property_get_float (config); if (priv->use_legacy) { for (j = 0; j < EQ_CHANNELS; j++) { set_gain (i, j, xmms_eq_gain_scale (gain, FALSE)); } } } for (i=0; i<EQ_MAX_BANDS; i++) { gchar buf[16]; g_snprintf (buf, sizeof (buf), "gain%02d", i); config = xmms_xform_config_lookup (xform, buf); g_return_val_if_fail (config, FALSE); priv->gain[i] = config; xmms_config_property_callback_set (config, xmms_eq_gain_changed, priv); gain = xmms_config_property_get_float (config); if (!priv->use_legacy) { for (j = 0; j < EQ_CHANNELS; j++) { set_gain (i, j, xmms_eq_gain_scale (gain, FALSE)); } } } init_iir (); srate = xmms_xform_indata_get_int (xform, XMMS_STREAM_TYPE_FMT_SAMPLERATE); if (priv->use_legacy) { config_iir (srate, EQ_BANDS_LEGACY, 1); } else { config_iir (srate, priv->bands, 0); } xmms_xform_outdata_type_copy (xform); XMMS_DBG ("Equalizer initialized successfully!"); return TRUE; }
static gboolean xmms_opus_init (xmms_xform_t *xform) { xmms_opus_data_t *data; gint ret; guint playtime; const gchar *metakey; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_opus_data_t, 1), data->callbacks.read = opus_callback_read; data->callbacks.close = opus_callback_close; data->callbacks.tell = opus_callback_tell; data->callbacks.seek = opus_callback_seek; data->current = -1; xmms_xform_private_data_set (xform, data); data->opusfile = op_open_callbacks (xform, &data->callbacks, NULL, 0, &ret); if (ret) { return FALSE; } playtime = op_pcm_total (data->opusfile, -1) / 48000; if (playtime != OP_EINVAL) { gint filesize; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE; if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) { xmms_opus_set_duration (xform, playtime); } } xmms_opus_read_metadata (xform, data); /* xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_FLOAT, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, 48000, XMMS_STREAM_TYPE_END); */ xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, data->channels, XMMS_STREAM_TYPE_FMT_SAMPLERATE, 48000, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_mid1_init (xmms_xform_t *xform) { xmms_error_t error; xmms_mid1_data_t *data; guchar buf[4096]; gulong len; gint ret; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mid1_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); ret = xmms_xform_read (xform, buf, 4, &error); if (strncmp ((char *)buf, "RIFF", 4) == 0) { /* This is an .rmi file, find the data chunk */ gboolean is_rmid = FALSE; /* Skip the RIFF length and RMID type (we wouldn't be here if it wasn't * RMID thanks to xmms_magic_add above.) */ xmms_xform_read (xform, buf, 8, &error); /* skip RIFF length */ for (;;) { /* Get chunk type and length */ xmms_xform_read (xform, buf, 8, &error); if (strncmp ((char *)buf, "data", 4) == 0) { /* We found the data chunk, the rest is just a normal MIDI file. We * chew up the "MThd" signature though, as the code below expects it * to be gone (as it would in a normal MIDI file when we eat it to * check the RIFF header above.) */ is_rmid = TRUE; ret = xmms_xform_read (xform, buf, 4, &error); break; } /* If we're here, this isn't the "data" chunk, so skip over it */ len = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24); while (len > 0) { ret = xmms_xform_read (xform, buf, MIN (len, sizeof (buf)), &error); if (ret < 1) break; len -= ret; } } if (!is_rmid) { xmms_log_error ("RMID file has no 'data' chunk!"); goto cleanup; } } /* Once we get here we're just after the MThd signature */ ret = xmms_xform_read (xform, buf, 10, &error); gint header_len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; if (header_len != 6) { xmms_log_error ("Unexpected MThd header length"); goto cleanup; } /* Don't need to check it's a type-0 or 1 as the magic matching did it */ guint track_count = (buf[6] << 8) | buf[7]; if (track_count == 0) { xmms_log_error ("MIDI file has no tracks?!"); goto cleanup; } guint ticks_per_quarter_note = (buf[8] << 8) | buf[9]; if (ticks_per_quarter_note & 0x8000) { /* TODO */ xmms_log_error ("SMPTE timing not implemented"); goto cleanup; } xmms_xform_auxdata_set_int (xform, "tempo", ticks_per_quarter_note); data->chunked_data = g_string_sized_new (1024); /* Load all the tracks */ while (xmms_xform_read (xform, buf, 8, &error) == 8) { len = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; XMMS_DBG ("%.4s len is %lu", buf, len); if (strncmp ((char *)buf, "MTrk", 4) != 0) { XMMS_DBG ("Ignoring unknown chunk: %.4s", buf); /* Skip over the chunk - we don't use seek as it's not always implemented * by the parent xform. */ while (len > 0) { ret = xmms_xform_read (xform, buf, MIN (len, sizeof (buf)), &error); if (ret < 1) break; len -= ret; } } else { /* Append the big-endian length */ g_string_append_len (data->chunked_data, (gchar *)&buf[4], 4); for (;;) { gulong amt = MIN (len, sizeof (buf)); if (amt == 0) break; ret = xmms_xform_read (xform, (gchar *)buf, amt, &error); if (ret != amt) { /* Short read */ XMMS_DBG ("Short read"); goto cleanup; } g_string_append_len (data->chunked_data, (gchar *)buf, amt); len -= amt; } } } xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/miditracks", XMMS_STREAM_TYPE_FMT_CHANNELS, 16, XMMS_STREAM_TYPE_END); return TRUE; cleanup: if (data->chunked_data) g_string_free (data->chunked_data, TRUE); g_free (data); return FALSE; }
static gboolean xmms_mp4_init (xmms_xform_t *xform) { xmms_mp4_data_t *data; xmms_error_t error; gint bytes_read; guchar *tmpbuf; guint tmpbuflen; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_mp4_data_t, 1); data->outbuf = g_string_new (NULL); data->buffer_size = MP4_BUFFER_SIZE; xmms_xform_private_data_set (xform, data); data->sampleid = 1; data->numsamples = 0; bytes_read = xmms_xform_read (xform, (gchar *) data->buffer + data->buffer_length, data->buffer_size - data->buffer_length, &error); data->buffer_length += bytes_read; if (bytes_read < 8) { XMMS_DBG ("Not enough bytes to check the MP4 header"); goto err; } /* * MP4 not supported (yet) on non-seekable transport * this needs little tweaking in mp4ff at least */ if (xmms_xform_seek (xform, 0, XMMS_XFORM_SEEK_CUR, &error) < 0) { XMMS_DBG ("Non-seekable transport on MP4 not yet supported"); goto err; } data->mp4ff_cb = g_new0 (mp4ff_callback_t, 1); data->mp4ff_cb->read = xmms_mp4_read_callback; data->mp4ff_cb->seek = xmms_mp4_seek_callback; data->mp4ff_cb->user_data = xform; data->mp4ff = mp4ff_open_read (data->mp4ff_cb); if (!data->mp4ff) { XMMS_DBG ("Error opening mp4 demuxer\n"); goto err;; } data->track = xmms_mp4_get_track (xform, data->mp4ff); if (data->track < 0) { XMMS_DBG ("Can't find suitable audio track from MP4 file\n"); goto err; } data->numsamples = mp4ff_num_samples (data->mp4ff, data->track); mp4ff_get_decoder_config (data->mp4ff, data->track, &tmpbuf, &tmpbuflen); xmms_xform_auxdata_set_bin (xform, "decoder_config", tmpbuf, tmpbuflen); g_free (tmpbuf); xmms_mp4_get_mediainfo (xform); XMMS_DBG ("MP4 demuxer inited successfully!"); return TRUE; err: g_free (data->mp4ff_cb); g_string_free (data->outbuf, TRUE); g_free (data); return FALSE; }
static gboolean xmms_sid_init (xmms_xform_t *xform) { xmms_sid_data_t *data; const char *subtune; gint ret; data = g_new0 (xmms_sid_data_t, 1); data->wrapper = sidplay_wrapper_init (); xmms_xform_private_data_set (xform, data); data->buffer = g_string_new (""); for (;;) { xmms_error_t error; gchar buf[4096]; gint ret; ret = xmms_xform_read (xform, buf, sizeof (buf), &error); if (ret == -1) { XMMS_DBG ("Error reading sid file"); return FALSE; } if (ret == 0) { break; } g_string_append_len (data->buffer, buf, ret); } ret = sidplay_wrapper_load (data->wrapper, data->buffer->str, data->buffer->len); if (ret < 0) { XMMS_DBG ("Couldn't load sid file"); return FALSE; } if (xmms_xform_metadata_get_str (xform, "subtune", &subtune)) { int num; num = atoi (subtune); if (num < 1 || num > sidplay_wrapper_subtunes (data->wrapper)) { XMMS_DBG ("Invalid subtune index"); return FALSE; } sidplay_wrapper_set_subtune (data->wrapper, num); } xmms_sid_get_media_info (xform); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, 2, XMMS_STREAM_TYPE_FMT_SAMPLERATE, 44100, XMMS_STREAM_TYPE_END); return TRUE; }
static gboolean xmms_cdda_init (xmms_xform_t *xform) { CdIo_t *cdio = NULL; cdrom_drive_t *drive = NULL; const gchar *url; gchar **url_data = NULL; gchar *url_end; xmms_cdda_data_t *data; guint playtime; lsn_t first_lsn; track_t track; gchar *disc_id = NULL; gchar *cddb_id = NULL; xmms_config_property_t *val; const gchar *device; const gchar *metakey; gboolean ret = TRUE; g_return_val_if_fail (xform, FALSE); url = xmms_xform_indata_get_str (xform, XMMS_STREAM_TYPE_URL); if (g_ascii_strcasecmp (url, "cdda://") == 0) { xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "application/x-xmms2-playlist-entries", XMMS_STREAM_TYPE_END); return TRUE; } val = xmms_xform_config_lookup (xform, "device"); device = xmms_config_property_get_string (val); if (!get_disc_ids (device, &disc_id, &cddb_id, 0)) { return FALSE; } url += 7; url_data = g_strsplit (url, "/", 2); if (g_ascii_strcasecmp (url_data[0], disc_id)) { xmms_log_error ("Wrong disc inserted."); ret = FALSE; goto end; } if (url_data[1] == NULL) { xmms_log_error ("Missing track number."); ret = FALSE; goto end; } track = strtol (url_data[1], &url_end, 10); if (url_data[1] == url_end) { xmms_log_error ("Invalid track, need a number."); ret = FALSE; goto end; } cdio = open_cd (xform); if (!cdio) { ret = FALSE; goto end; } drive = cdio_cddap_identify_cdio (cdio, 1, NULL); if (!drive) { xmms_log_error ("Failed to identify drive."); ret = FALSE; goto end; } if (cdio_cddap_open (drive)) { xmms_log_error ("Unable to open disc."); ret = FALSE; goto end; } first_lsn = cdio_cddap_track_firstsector (drive, track); if (first_lsn == -1) { xmms_log_error ("No such track."); ret = FALSE; goto end; } data = g_new (xmms_cdda_data_t, 1); data->cdio = cdio; data->drive = drive; data->track = track; data->first_lsn = first_lsn; data->last_lsn = cdio_cddap_track_lastsector (drive, data->track); data->current_lsn = first_lsn; data->buf_used = CDIO_CD_FRAMESIZE_RAW; playtime = (data->last_lsn - data->first_lsn) * 1000.0 / CDIO_CD_FRAMES_PER_SEC; metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION; xmms_xform_metadata_set_int (xform, metakey, playtime); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE; xmms_xform_metadata_set_int (xform, metakey, 141120); xmms_xform_metadata_set_str (xform, "disc_id", url_data[0]); xmms_xform_metadata_set_str (xform, "cddb_id", cddb_id); metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR; xmms_xform_metadata_set_int (xform, metakey, track); xmms_xform_private_data_set (xform, data); xmms_xform_outdata_type_add (xform, XMMS_STREAM_TYPE_MIMETYPE, "audio/pcm", XMMS_STREAM_TYPE_FMT_FORMAT, XMMS_SAMPLE_FORMAT_S16, XMMS_STREAM_TYPE_FMT_CHANNELS, 2, XMMS_STREAM_TYPE_FMT_SAMPLERATE, 44100, XMMS_STREAM_TYPE_END); end: /* These are to be destroyed in every cases... */ g_free (cddb_id); g_free (disc_id); g_strfreev (url_data); /* destroy cdio/drive in case of failure */ if (!ret) { if (drive) { cdio_cddap_close_no_free_cdio (drive); } if (cdio) { cdio_destroy (cdio); } } return ret; }
static gboolean xmms_replaygain_init (xmms_xform_t *xform) { xmms_replaygain_data_t *data; xmms_config_property_t *cfgv; xmms_sample_format_t fmt; g_return_val_if_fail (xform, FALSE); data = g_new0 (xmms_replaygain_data_t, 1); g_return_val_if_fail (data, FALSE); xmms_xform_private_data_set (xform, data); cfgv = xmms_xform_config_lookup (xform, "mode"); xmms_config_property_callback_set (cfgv, xmms_replaygain_config_changed, xform); data->mode = parse_mode (xmms_config_property_get_string (cfgv)); cfgv = xmms_xform_config_lookup (xform, "use_anticlip"); xmms_config_property_callback_set (cfgv, xmms_replaygain_config_changed, xform); data->use_anticlip = !!xmms_config_property_get_int (cfgv); cfgv = xmms_xform_config_lookup (xform, "preamp"); xmms_config_property_callback_set (cfgv, xmms_replaygain_config_changed, xform); data->preamp = pow (10.0, atof (xmms_config_property_get_string (cfgv)) / 20.0); cfgv = xmms_xform_config_lookup (xform, "enabled"); xmms_config_property_callback_set (cfgv, xmms_replaygain_config_changed, xform); data->enabled = !!xmms_config_property_get_int (cfgv); xmms_xform_outdata_type_copy (xform); compute_gain (xform, data); fmt = xmms_xform_indata_get_int (xform, XMMS_STREAM_TYPE_FMT_FORMAT); switch (fmt) { case XMMS_SAMPLE_FORMAT_S8: data->apply = apply_s8; break; case XMMS_SAMPLE_FORMAT_U8: data->apply = apply_u8; break; case XMMS_SAMPLE_FORMAT_S16: data->apply = apply_s16; break; case XMMS_SAMPLE_FORMAT_U16: data->apply = apply_u16; break; case XMMS_SAMPLE_FORMAT_S32: data->apply = apply_s32; break; case XMMS_SAMPLE_FORMAT_U32: data->apply = apply_u32; break; case XMMS_SAMPLE_FORMAT_FLOAT: data->apply = apply_float; break; case XMMS_SAMPLE_FORMAT_DOUBLE: data->apply = apply_double; break; default: /* we shouldn't ever get here, since we told the daemon * earlier about this list of supported formats. */ g_assert_not_reached (); break; } return TRUE; }