Esempio n. 1
0
File: midi.c Progetto: denemo/denemo
smf_event_t *
get_smf_event (double until_time)
{
  if (Denemo.project == NULL || Denemo.project->movement == NULL || Denemo.project->movement->smf == NULL)
    return NULL;
  smf_t *smf = Denemo.project->movement->smf;

  if (until_time > Denemo.project->movement->end_time)
    {
      until_time = Denemo.project->movement->end_time;
    }

  for (;;)
    {
      smf_event_t *event = smf_peek_next_event (smf);

      if (event == NULL || event->time_seconds >= until_time)
        {
          return NULL;
        }

      if (smf_event_is_metadata (event))
        {
          // consume metadata event and continue with the next one
          event = smf_get_next_event (smf);
          continue;
        }

      // consume the event
      event = smf_get_next_event (smf);
      return event;
    }
}
Esempio n. 2
0
static int
show_event(smf_event_t *event)
{
	int off = 0, i;
	char *decoded, *type;

	if (smf_event_is_metadata(event))
		type = "Metadata";
	else
		type = "Event";
	
	decoded = smf_event_decode(event);

	if (decoded == NULL) {
		decoded = malloc(BUFFER_SIZE);
		if (decoded == NULL) {
			g_critical("show_event: malloc failed.");
			return (-1);
		}

		off += snprintf(decoded + off, BUFFER_SIZE - off, "Unknown event:");

		for (i = 0; i < event->midi_buffer_length && i < 5; i++)
			off += snprintf(decoded + off, BUFFER_SIZE - off, " 0x%x", event->midi_buffer[i]);
	}

	g_message("%d: %s: %s, %f seconds, %d pulses, %d delta pulses", event->event_number, type, decoded,
	    event->time_seconds, event->time_pulses, event->delta_time_pulses);

	free(decoded);

	return (0);
}
Esempio n. 3
0
CAMLprim value ocaml_smf_event_is_metadata(value event)
{
    CAMLparam1(event);
    int ret;
    smf_event_t *e = get_event(event);
    ret = smf_event_is_metadata(e);
    CAMLreturn(Val_bool(ret));
}
Esempio n. 4
0
File: smf.c Progetto: Darko8/libsmf
/**
  * \return Nonzero if event is Tempo Change or Time Signature metaevent.
  */
int
smf_event_is_tempo_change_or_time_signature(const smf_event_t *event)
{
	if (!smf_event_is_metadata(event))
		return (0);

	assert(event->midi_buffer_length >= 2);

	if (event->midi_buffer[1] == 0x51 || event->midi_buffer[1] == 0x58)
		return (1);

	return (0);
}
Esempio n. 5
0
/**
 * \return Nonzero if event is System Realtime.
 */
int
smf_event_is_system_realtime(const smf_event_t *event)
{
	assert(event->midi_buffer);
	assert(event->midi_buffer_length > 0);

	if (smf_event_is_metadata(event))
		return (0);
	
	if (event->midi_buffer[0] >= 0xF8)
		return (1);

	return (0);
}
Esempio n. 6
0
/**
 * \return 1, if passed a metaevent containing text, that is, Text, Copyright,
 * Sequence/Track Name, Instrument, Lyric, Marker, Cue Point, Program Name,
 * or Device Name; 0 otherwise.
 */
int
smf_event_is_textual(const smf_event_t *event)
{
	if (!smf_event_is_metadata(event))
		return (0);

	if (event->midi_buffer_length < 4)
		return (0);

	if (event->midi_buffer[3] < 1 || event->midi_buffer[3] > 9)
		return (0);

	return (1);
}
Esempio n. 7
0
File: ui.c Progetto: hbkk/sequencer
static int
ui_load_state(ui_t *ui, char *filename)
{
    int i;
    smf_t *smf;
    smf_event_t *event;
    smf_track_t *track;
    jack_nframes_t frame;


    if (!filename) {
        ui->filename = ui_get_filename(ui, ".", "Load file: ");
    }

    if (ui->filename) {
        smf = smf_load(ui->filename);
        if (!smf) {
            free(ui->filename);
            ui->filename = NULL;

            return 0;
        }

        ui_send_clear(ui, ui->pattern);

        for (i = 0; i < 8; i++) {
            track = smf_get_track_by_number(smf, i + 1);
            if (!track) {
                continue;
            }

            while ((event = smf_track_get_next_event(track))) {
                if (smf_event_is_metadata(event)
                        || event->midi_buffer[0] == NOTEOFF) {
                    continue;
                }

                frame = ui_seconds_to_nframes(ui, event->time_seconds);

                ui_send_add(ui, event->midi_buffer[1], event->midi_buffer[2],
                    frame ? frame / (88200 / ui->steps) + 1 : 0, MAX_LEN, i);
            }
        }

        smf_delete(smf);
  	}

    return 1;
}
Esempio n. 8
0
/**
 * \return Textual representation of the event given, or NULL, if event is unknown.
 * Returned string looks like this:
 *
 * Note On, channel 1, note F#3, velocity 0
 *
 * You should free the returned string afterwards, using free(3).
 */
char *
smf_event_decode(const smf_event_t *event)
{
	int off = 0, channel;
	char *buf, note[5];

	if (smf_event_is_metadata(event))
		return (smf_event_decode_metadata(event));

	if (smf_event_is_system_realtime(event))
		return (smf_event_decode_system_realtime(event));

	if (smf_event_is_system_common(event))
		return (smf_event_decode_system_common(event));

	if (!smf_event_length_is_valid(event)) {
		g_critical("smf_event_decode: incorrect MIDI message length.");
		return (NULL);
	}

	buf = (char*)malloc(BUFFER_SIZE);
	if (buf == NULL) {
		g_critical("smf_event_decode: malloc failed.");
		return (NULL);
	}

	/* + 1, because user-visible channels used to be in range <1-16>. */
	channel = (event->midi_buffer[0] & 0x0F) + 1;

	switch (event->midi_buffer[0] & 0xF0) {
		case 0x80:
			note_from_int(note, event->midi_buffer[1]);
			off += snprintf(buf + off, BUFFER_SIZE - off, "Note Off, channel %d, note %s, velocity %d",
					channel, note, event->midi_buffer[2]);
			break;

		case 0x90:
			note_from_int(note, event->midi_buffer[1]);
			off += snprintf(buf + off, BUFFER_SIZE - off, "Note On, channel %d, note %s, velocity %d",
					channel, note, event->midi_buffer[2]);
			break;

		case 0xA0:
			note_from_int(note, event->midi_buffer[1]);
			off += snprintf(buf + off, BUFFER_SIZE - off, "Aftertouch, channel %d, note %s, pressure %d",
					channel, note, event->midi_buffer[2]);
			break;

		case 0xB0:
			off += snprintf(buf + off, BUFFER_SIZE - off, "Controller, channel %d, controller %d, value %d",
					channel, event->midi_buffer[1], event->midi_buffer[2]);
			break;

		case 0xC0:
			off += snprintf(buf + off, BUFFER_SIZE - off, "Program Change, channel %d, controller %d",
					channel, event->midi_buffer[1]);
			break;

		case 0xD0:
			off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Pressure, channel %d, pressure %d",
					channel, event->midi_buffer[1]);
			break;

		case 0xE0:
			off += snprintf(buf + off, BUFFER_SIZE - off, "Pitch Wheel, channel %d, value %d",
					channel, ((int)event->midi_buffer[2] << 7) | (int)event->midi_buffer[2]);
			break;

		default:
			free(buf);
			return (NULL);
	}

	assert(off <= BUFFER_SIZE);

	return (buf);
}
Esempio n. 9
0
static char *
smf_event_decode_metadata(const smf_event_t *event)
{
	int off = 0, mspqn, flats, isminor;
	char *buf;

	static const char *const major_keys[] = {"Fb", "Cb", "Gb", "Db", "Ab",
		"Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#", "G#"};

	static const char *const minor_keys[] = {"Dbm", "Abm", "Ebm", "Bbm", "Fm",
		"Cm", "Gm", "Dm", "Am", "Em", "Bm", "F#m", "C#m", "G#m", "D#m", "A#m", "E#m"};

	assert(smf_event_is_metadata(event));

	switch (event->midi_buffer[1]) {
		case 0x01:
			return (smf_event_decode_textual(event, "Text"));

		case 0x02:
			return (smf_event_decode_textual(event, "Copyright"));

		case 0x03:
			return (smf_event_decode_textual(event, "Sequence/Track Name"));

		case 0x04:
			return (smf_event_decode_textual(event, "Instrument"));

		case 0x05:
			return (smf_event_decode_textual(event, "Lyric"));

		case 0x06:
			return (smf_event_decode_textual(event, "Marker"));

		case 0x07:
			return (smf_event_decode_textual(event, "Cue Point"));

		case 0x08:
			return (smf_event_decode_textual(event, "Program Name"));

		case 0x09:
			return (smf_event_decode_textual(event, "Device (Port) Name"));

		default:
			break;
	}

	buf = (char*)malloc(BUFFER_SIZE);
	if (buf == NULL) {
		g_critical("smf_event_decode_metadata: malloc failed.");
		return (NULL);
	}

	switch (event->midi_buffer[1]) {
		case 0x00:
			off += snprintf(buf + off, BUFFER_SIZE - off, "Sequence number");
			break;

		/* http://music.columbia.edu/pipermail/music-dsp/2004-August/061196.html */
		case 0x20:
			if (event->midi_buffer_length < 4) {
				g_critical("smf_event_decode_metadata: truncated MIDI message.");
				goto error;
			}

			off += snprintf(buf + off, BUFFER_SIZE - off, "Channel Prefix: %d", event->midi_buffer[3]);
			break;

		case 0x21:
			if (event->midi_buffer_length < 4) {
				g_critical("smf_event_decode_metadata: truncated MIDI message.");
				goto error;
			}

			off += snprintf(buf + off, BUFFER_SIZE - off, "MIDI Port: %d", event->midi_buffer[3]);
			break;

		case 0x2F:
			off += snprintf(buf + off, BUFFER_SIZE - off, "End Of Track");
			break;

		case 0x51:
			if (event->midi_buffer_length < 6) {
				g_critical("smf_event_decode_metadata: truncated MIDI message.");
				goto error;
			}

			mspqn = (event->midi_buffer[3] << 16) + (event->midi_buffer[4] << 8) + event->midi_buffer[5];

			off += snprintf(buf + off, BUFFER_SIZE - off, "Tempo: %d microseconds per quarter note, %.2f BPM",
				mspqn, 60000000.0 / (double)mspqn);
			break;

		case 0x54:
			off += snprintf(buf + off, BUFFER_SIZE - off, "SMPTE Offset");
			break;

		case 0x58:
			if (event->midi_buffer_length < 7) {
				g_critical("smf_event_decode_metadata: truncated MIDI message.");
				goto error;
			}

			off += snprintf(buf + off, BUFFER_SIZE - off,
				"Time Signature: %d/%d, %d clocks per click, %d notated 32nd notes per quarter note",
				event->midi_buffer[3], (int)pow((double)2, event->midi_buffer[4]), event->midi_buffer[5],
				event->midi_buffer[6]);
			break;

		case 0x59:
			if (event->midi_buffer_length < 5) {
				g_critical("smf_event_decode_metadata: truncated MIDI message.");
				goto error;
			}

			flats = event->midi_buffer[3];
			isminor = event->midi_buffer[4];

			if (isminor != 0 && isminor != 1) {
				g_critical("smf_event_decode_metadata: last byte of the Key Signature event has invalid value %d.", isminor);
				goto error;
			}

			off += snprintf(buf + off, BUFFER_SIZE - off, "Key Signature: ");

			if (flats > 8 && flats < 248) {
				off += snprintf(buf + off, BUFFER_SIZE - off, "%d %s, %s key", abs((int8_t)flats),
					flats > 127 ? "flats" : "sharps", isminor ? "minor" : "major");
			} else {
				int i = (flats - 248) & 255;

				assert(i >= 0 && (size_t)i < sizeof(minor_keys) / sizeof(*minor_keys));
				assert(i >= 0 && (size_t)i < sizeof(major_keys) / sizeof(*major_keys));

				if (isminor)
					off += snprintf(buf + off, BUFFER_SIZE - off, "%s", minor_keys[i]);
				else
					off += snprintf(buf + off, BUFFER_SIZE - off, "%s", major_keys[i]);
			}

			break;

		case 0x7F:
			off += snprintf(buf + off, BUFFER_SIZE - off, "Proprietary (aka Sequencer) Event, length %zu",
				event->midi_buffer_length);
			break;

		default:
			goto error;
	}

	assert (off <= BUFFER_SIZE);
	return (buf);

error:
	free(buf);

	return (NULL);
}
Esempio n. 10
0
static void
process_midi_output(jack_nframes_t nframes)
{
	int		i, t, bytes_remaining, track_number;
	unsigned char  *buffer, tmp_status;
	void		*port_buffers[MAX_NUMBER_OF_TRACKS];
	jack_nframes_t	last_frame_time;
	jack_transport_state_t transport_state;
	static jack_transport_state_t previous_transport_state = JackTransportStopped;
	static int previous_playback_started = -1;
	static int previous_playback_paused = 0;

	for (i = 0; i <= smf->number_of_tracks; i++) {
		port_buffers[i] = jack_port_get_buffer(output_ports[i], nframes);

		if (port_buffers[i] == NULL) {
			warn_from_jack_thread_context("jack_port_get_buffer failed, cannot send anything.");
			return;
		}

#ifdef JACK_MIDI_NEEDS_NFRAMES
		jack_midi_clear_buffer(port_buffers[i], nframes);
#else
		jack_midi_clear_buffer(port_buffers[i]);
#endif

		if (just_one_output)
			break;
	}

	if (ctrl_c_pressed) {
		send_all_sound_off(port_buffers, nframes);
		
		/* The idea here is to exit at the second time process_midi_output gets called.
		   Otherwise, All Sound Off won't be delivered. */
		ctrl_c_pressed++;
		if (ctrl_c_pressed >= 3)
			exit(0);

		return;
	}

	// g_debug("PROCESS CALLBACK!!!");

	if (playback_paused) {
		if (!previous_playback_paused) {
			send_all_sound_off(port_buffers, nframes);
		}
		previous_playback_paused = playback_paused;
		return;
	}
	previous_playback_paused = playback_paused;

	if (use_transport) {

		// if (!ready_to_roll) return;

		transport_state = jack_transport_query(jack_client, NULL);

		if (transport_state == JackTransportStopped) {
			if (previous_transport_state == JackTransportRolling) {
				send_all_sound_off(port_buffers, nframes);
			}
			playback_started = -1;
		}

		if (transport_state == JackTransportStarting) {
			playback_started = -1;
		}

		if (transport_state == JackTransportRolling) {
			if (previous_transport_state != JackTransportRolling) {
				jack_position_t position;
				jack_transport_query(jack_client, &position);
				song_position = position.frame;
				playback_started = jack_last_frame_time(jack_client);
			}
		}

		previous_transport_state = transport_state;
	}
	else {
		if (playback_started == -1) {
			if (previous_playback_started >= 0) {
				send_all_sound_off(port_buffers, nframes);
				send_sond_end();
			}
		}
		previous_playback_started = playback_started;
	}


	/* End of song already? */
	if (playback_started < 0)
		return;

	last_frame_time = jack_last_frame_time(jack_client);

	/* We may push at most one byte per 0.32ms to stay below 31.25 Kbaud limit. */
	bytes_remaining = nframes_to_ms(nframes) * rate_limit;

	double loop_offset = loop_song(smf);

	for (;;) {

		smf_event_t *event = smf_peek_next_event(smf);

		int end_of_song = 0;
		int is_meta_event = 0;

		if (event == NULL) {
			end_of_song = 1;
		}
		else if (smf_event_is_metadata(event)) {
			is_meta_event = 1;
			char *decoded = smf_event_decode(event);
			if (decoded) {
				if (!be_quiet)
					g_debug("Metadata: %s", decoded);
				end_of_song = process_meta_event(decoded);
				free(decoded);
			}
		}

		if (end_of_song) {
			if (!be_quiet)
				g_debug("End of song.");
			playback_started = -1;

			if (!use_transport)
				ctrl_c_pressed = 1;
			break;
		}

		if (is_meta_event) {
			smf_event_t *ret = smf_get_next_event(smf);
			assert(ret != 0);
			continue;
		}

		bytes_remaining -= event->midi_buffer_length;

		if (rate_limit > 0.0 && bytes_remaining <= 0) {
			warn_from_jack_thread_context("Rate limiting in effect.");
			break;
		}

		// t = seconds_to_nframes(event->time_seconds) + playback_started - song_position + nframes - last_frame_time;
		t = seconds_to_nframes(event->time_seconds + loop_offset) + playback_started - song_position - last_frame_time;

		/* If computed time is too much into the future, we'll need
		   to send it later. */
		if (t >= (int)nframes)
			break;

		/* If computed time is < 0, we missed a cycle because of xrun. */
		if (t < 0)
			t = 0;

		assert(event->track->track_number >= 0 && event->track->track_number <= MAX_NUMBER_OF_TRACKS);

		/* We will send this event; remove it from the queue. */
		smf_event_t *ret = smf_get_next_event(smf);
		assert(ret != 0);

		/* First, send it via midi_out. */
		track_number = 0;

#ifdef JACK_MIDI_NEEDS_NFRAMES
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length, nframes);
#else
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length);
#endif

		if (buffer == NULL) {
			warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST.");
			break;
		}

		memcpy(buffer, event->midi_buffer, event->midi_buffer_length);

		/* Ignore per-track outputs? */
		if (just_one_output)
			continue;

		/* Send it via proper output port. */
		track_number = event->track->track_number;

#ifdef JACK_MIDI_NEEDS_NFRAMES
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length, nframes);
#else
		buffer = jack_midi_event_reserve(port_buffers[track_number], t, event->midi_buffer_length);
#endif

		if (buffer == NULL) {
			warn_from_jack_thread_context("jack_midi_event_reserve failed, NOTE LOST.");
			break;
		}

		/* Before sending, reset channel to 0. XXX: Not very pretty. */
		assert(event->midi_buffer_length >= 1);

		tmp_status = event->midi_buffer[0];

		if (event->midi_buffer[0] >= 0x80 && event->midi_buffer[0] <= 0xEF)
			event->midi_buffer[0] &= 0xF0;

		memcpy(buffer, event->midi_buffer, event->midi_buffer_length);

		event->midi_buffer[0] = tmp_status;
	}
}