Example #1
0
static gboolean
xmms_faad_gapless_try (xmms_xform_t *xform)
{
	xmms_faad_data_t *data;
	gint64 start = 0, stop = 0;

	g_return_val_if_fail (xform, FALSE);
	data = xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, FALSE);

	xmms_xform_auxdata_get_int64 (xform, "startsamples", &start);
	if (start == 0) {
		XMMS_DBG ("First frame of AAC should be ignored, but is not. Trying to fix.");
		start = xmms_faad_get_framesize (xform);
		if (start == 0) {
			XMMS_DBG ("No luck. Couldn't get the framesize.");
		}
	}
	if (start != 0) {
		xmms_xform_auxdata_set_int (xform, "startsamples", start);
	}

	xmms_xform_auxdata_get_int64 (xform, "stopsamples", &stop);
	if (stop != 0) {
		xmms_xform_auxdata_set_int (xform, "stopsamples", stop);
	}

	return (start != 0) || (stop != 0);
}
Example #2
0
gint
xmms_asf_get_track (xmms_xform_t *xform, asf_file_t *file)
{
    xmms_asf_data_t *data;
    uint8_t stream_count;
    gint i;

    g_return_val_if_fail (xform, -1);

    data = xmms_xform_private_data_get (xform);
    g_return_val_if_fail (data, -1);

    stream_count = asf_get_stream_count (file);

    for (i=1; i <= stream_count; i++) {
        asf_stream_t *stream = asf_get_stream (file, i);
        if (stream->type == ASF_STREAM_TYPE_AUDIO &&
                !(stream->flags & ASF_STREAM_FLAG_HIDDEN)) {
            asf_waveformatex_t *wfx = stream->properties;
            const gchar *mimetype;

            if (wfx->wFormatTag == 0x160)
                mimetype = "audio/x-ffmpeg-wmav1";
            else if (wfx->wFormatTag == 0x161)
                mimetype = "audio/x-ffmpeg-wmav2";
            else
                continue;

            data->samplerate = wfx->nSamplesPerSec;
            data->channels = wfx->nChannels;
            data->bitrate = wfx->nAvgBytesPerSec * 8;

            xmms_xform_auxdata_set_bin (xform,
                                        "decoder_config",
                                        wfx->data,
                                        wfx->cbSize);

            xmms_xform_auxdata_set_int (xform,
                                        "block_align",
                                        wfx->nBlockAlign);

            xmms_xform_auxdata_set_int (xform,
                                        "bitrate",
                                        data->bitrate);

            xmms_xform_outdata_type_add (xform,
                                         XMMS_STREAM_TYPE_MIMETYPE,
                                         mimetype,
                                         XMMS_STREAM_TYPE_FMT_SAMPLERATE,
                                         data->samplerate,
                                         XMMS_STREAM_TYPE_FMT_CHANNELS,
                                         data->channels,
                                         XMMS_STREAM_TYPE_END);

            return i;
        }
    }

    return -1;
}
Example #3
0
static gboolean
xmms_mp4_gapless_set (xmms_xform_t *xform, guint64 startsamples, guint64 stopsamples)
{
	g_return_val_if_fail ((gint64)startsamples >= 0, FALSE);
	g_return_val_if_fail ((gint64)stopsamples >= 0, FALSE);
	g_return_val_if_fail (startsamples <= stopsamples, FALSE);

	xmms_xform_auxdata_set_int (xform, "startsamples", startsamples);
	xmms_xform_auxdata_set_int (xform, "stopsamples", stopsamples);

	return TRUE;
}
Example #4
0
File: mp4.c Project: chrippa/xmms2
static gint
xmms_mp4_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
{
	xmms_mp4_data_t *data;
	guint size, bytes_read = 0;

	data = xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, -1);

	size = MIN (data->outbuf->len, len);
	while (size == 0) {
		guchar *tmpbuf;
		guint tmpbuflen;
		gint duration, offset;

		if (data->sampleid >= data->numsamples) {
			XMMS_DBG ("MP4 EOF");
			return 0;
		}

		bytes_read = mp4ff_read_sample (data->mp4ff, data->track,
		                                data->sampleid, &tmpbuf,
		                                &tmpbuflen);
		offset = mp4ff_get_sample_offset (data->mp4ff, data->track,
		                                  data->sampleid);
		duration = mp4ff_get_sample_duration (data->mp4ff, data->track,
		                                      data->sampleid);
		data->sampleid++;

		xmms_xform_auxdata_set_int (xform, "frame_offset", offset);
		xmms_xform_auxdata_set_int (xform, "frame_duration", duration);

		if (bytes_read > 0) {
			g_string_append_len (data->outbuf, (gchar *) tmpbuf, tmpbuflen);
			g_free (tmpbuf);
		}

		size = MIN (data->outbuf->len, len);
	}

	memcpy (buf, data->outbuf->str, size);
	g_string_erase (data->outbuf, 0, size);
	return size;
}
Example #5
0
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);
		}
Example #6
0
File: mid1.c Project: chrippa/xmms2
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;
}