Beispiel #1
0
/**
 * Puts MIDI data extracted from from "buf" into "event" and number of consumed bytes into "len".
 * In case valid status is not found, it uses "last_status" (so called "running status").
 * Returns 0 iff everything went OK, value < 0 in case of error.
 */
static int
extract_midi_event(const unsigned char *buf, const size_t buffer_length, smf_event_t *event, uint32_t *len, int last_status)
{
	int status;
	int32_t message_length;
	const unsigned char *c = buf;

	assert(buffer_length > 0);

	/* Is the first byte the status byte? */
	if (is_status_byte(*c)) {
		status = *c;
		c++;

	} else {
		/* No, we use running status then. */
		status = last_status;
	}

	if (!is_status_byte(status)) {
		g_critical("SMF error: bad status byte (MSB is zero).");
		return (-1);
	}

	if (is_sysex_byte(status))
		return (extract_sysex_event(buf, buffer_length, event, len, last_status));

	if (is_escape_byte(status))
		return (extract_escaped_event(buf, buffer_length, event, len, last_status));

	/* At this point, "c" points to first byte following the status byte. */
	message_length = expected_message_length(status, c, buffer_length - (c - buf));

	if (message_length < 0)
		return (-3);

	if ((size_t)message_length > buffer_length - (c - buf) + 1) {
		g_critical("End of buffer in extract_midi_event().");
		return (-5);
	}

	event->midi_buffer_length = message_length;
	event->midi_buffer = (uint8_t*)malloc(event->midi_buffer_length);
	if (event->midi_buffer == NULL) {
		g_critical("Cannot allocate memory in extract_midi_event(): %s", strerror(errno));
		return (-4);
	}

	event->midi_buffer[0] = status;
	memcpy(event->midi_buffer + 1, c, message_length - 1);

	*len = c + message_length - 1 - buf;

	return (0);
}
Beispiel #2
0
/* XXX: this routine requires some more work to detect more errors. */
int
smf_event_is_valid(const smf_event_t *event)
{
	assert(event);
	assert(event->midi_buffer);
	assert(event->midi_buffer_length >= 1);

	if (!is_status_byte(event->midi_buffer[0])) {
		g_critical("First byte of MIDI message is not a valid status byte.");

		return (0);
	}

	if (!smf_event_length_is_valid(event))
		return (0);

	return (1);
}
Beispiel #3
0
/**
 * Allocates an smf_event_t structure and fills it with at most three bytes of data.
 * For example, if you need to create Note On event, do something like this:
 *
 * smf_event_new_from_bytes(0x90, 0x3C, 0x7f);
 *
 * To create event for MIDI message that is shorter than three bytes, do something
 * like this:
 *
 * smf_event_new_from_bytes(0xC0, 0x42, -1);
 * 
 * \param first_byte First byte of MIDI message.  Must be valid status byte.
 * \param second_byte Second byte of MIDI message or -1, if message is one byte long.
 * \param third_byte Third byte of MIDI message or -1, if message is two bytes long.
 * \return Event containing MIDI data or NULL.
 */
smf_event_t *
smf_event_new_from_bytes(int first_byte, int second_byte, int third_byte)
{
	int len;

	smf_event_t *event;

	event = smf_event_new();
	if (event == NULL)
		return (NULL);

	if (first_byte < 0) {
		g_critical("First byte of MIDI message cannot be < 0");
		smf_event_delete(event);

		return (NULL);
	}

	if (first_byte > 255) {
		g_critical("smf_event_new_from_bytes: first byte is %d, which is larger than 255.", first_byte);
		return (NULL);
	}

	if (!is_status_byte(first_byte)) {
		g_critical("smf_event_new_from_bytes: first byte is not a valid status byte.");
		return (NULL);
	}


	if (second_byte < 0)
		len = 1;
	else if (third_byte < 0)
		len = 2;
	else
		len = 3;

	if (len > 1) {
		if (second_byte > 255) {
			g_critical("smf_event_new_from_bytes: second byte is %d, which is larger than 255.", second_byte);
			return (NULL);
		}

		if (is_status_byte(second_byte)) {
			g_critical("smf_event_new_from_bytes: second byte cannot be a status byte.");
			return (NULL);
		}
	}

	if (len > 2) {
		if (third_byte > 255) {
			g_critical("smf_event_new_from_bytes: third byte is %d, which is larger than 255.", third_byte);
			return (NULL);
		}

		if (is_status_byte(third_byte)) {
			g_critical("smf_event_new_from_bytes: third byte cannot be a status byte.");
			return (NULL);
		}
	}

	event->midi_buffer_length = len;
	event->midi_buffer = malloc(event->midi_buffer_length);
	if (event->midi_buffer == NULL) {
		g_critical("Cannot allocate MIDI buffer structure: %s", strerror(errno));
		smf_event_delete(event);

		return (NULL); 
	}

	event->midi_buffer[0] = first_byte;
	if (len > 1)
		event->midi_buffer[1] = second_byte;
	if (len > 2)
		event->midi_buffer[2] = third_byte;

	return (event);
}
Beispiel #4
0
/**
 * Returns expected length of the midi message (including the status byte), in bytes, for the given status byte.
 * The "second_byte" points to the expected second byte of the MIDI message.  "buffer_length" is the buffer
 * length limit, counting from "second_byte".  Returns value < 0 iff there was an error.
 */
static int32_t
expected_message_length(unsigned char status, const unsigned char *second_byte, const size_t buffer_length)
{
	/* Make sure this really is a valid status byte. */
	assert(is_status_byte(status));

	/* We cannot use this routine for sysexes. */
	assert(!is_sysex_byte(status));

	/* We cannot use this routine for escaped events. */
	assert(!is_escape_byte(status));

	/* Is this a metamessage? */
	if (status == 0xFF) {
		if (buffer_length < 2) {
			g_critical("SMF error: end of buffer in expected_message_length().");
			return (-1);
		}

		/*
		 * Format of this kind of messages is like this: 0xFF 0xwhatever 0xlength and then "length" bytes.
		 * Second byte points to this:                        ^^^^^^^^^^
		 */
		return (*(second_byte + 1) + 3);
	}

	if ((status & 0xF0) == 0xF0) {
		switch (status) {
			case 0xF2: /* Song Position Pointer. */
				return (3);

			case 0xF1: /* MTC Quarter Frame. */
			case 0xF3: /* Song Select. */
				return (2);

			case 0xF6: /* Tune Request. */
			case 0xF8: /* MIDI Clock. */
			case 0xF9: /* Tick. */
			case 0xFA: /* MIDI Start. */
			case 0xFB: /* MIDI Continue. */
			case 0xFC: /* MIDI Stop. */
			case 0xFE: /* Active Sense. */
				return (1);

			default:
				g_critical("SMF error: unknown 0xFx-type status byte '0x%x'.", status);
				return (-2);
		}
	}

	/* Filter out the channel. */
	status &= 0xF0;

	switch (status) {
		case 0x80: /* Note Off. */
		case 0x90: /* Note On. */
		case 0xA0: /* AfterTouch. */
		case 0xB0: /* Control Change. */
		case 0xE0: /* Pitch Wheel. */
			return (3);	

		case 0xC0: /* Program Change. */
		case 0xD0: /* Channel Pressure. */
			return (2);

		default:
			g_critical("SMF error: unknown status byte '0x%x'.", status);
			return (-3);
	}
}