Ejemplo n.º 1
0
Archivo: smf.c Proyecto: Darko8/libsmf
/**
  * Seeks the SMF to the given position.  For example, after seeking to 10 pulses,
  * smf_get_next_event will return first event that happens after the first ten pulses.
  * \return 0 if everything went ok, nonzero otherwise.
  */
int
smf_seek_to_pulses(smf_t *smf, int pulses)
{
	smf_event_t *event;

	assert(pulses >= 0);

	smf_rewind(smf);

#if 0
	g_debug("Seeking to %d pulses.", pulses);
#endif

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

		if (event == NULL) {
			g_critical("Trying to seek past the end of song.");
			return (-1);
		}

		if (event->time_pulses < pulses)
			smf_skip_next_event(smf);
		else
			break;
	}

	smf->last_seek_position = event->time_seconds;

	return (0);
}
Ejemplo n.º 2
0
Archivo: smf.c Proyecto: Darko8/libsmf
/**
  * Seeks the SMF to the given event.  After calling this routine, smf_get_next_event
  * will return the event that was the second argument of this call.
  */
int
smf_seek_to_event(smf_t *smf, const smf_event_t *target)
{
	smf_event_t *event;

	smf_rewind(smf);

#if 0
	g_debug("Seeking to event %d, track %d.", target->event_number, target->track->track_number);
#endif

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

		/* There can't be NULL here, unless "target" is not in this smf. */
		assert(event);

		if (event != target)
			smf_skip_next_event(smf);
		else
			break;
	}	

	smf->last_seek_position = event->time_seconds;

	return (0);
}
Ejemplo n.º 3
0
Archivo: midi.c Proyecto: 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;
    }
}
Ejemplo n.º 4
0
void timebase_callback(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t *pos, int new_pos, void *notused)
{
	double min;		/* Minutes since frame 0. */
	long abs_tick;		/* Ticks since frame 0. */
	long abs_beat;		/* Beats since frame 0. */
	smf_tempo_t *tempo;
	static smf_tempo_t *previous_tempo = NULL;

	smf_event_t *event = smf_peek_next_event(smf);
	if (event == NULL)
		return;

	tempo = smf_get_tempo_by_pulses(smf, event->time_pulses);

	assert(tempo);

	if (new_pos || previous_tempo != tempo) {
		pos->valid = JackPositionBBT;
		pos->beats_per_bar = tempo->numerator;
		pos->beat_type = 1.0 / (double)tempo->denominator;
		pos->ticks_per_beat = event->track->smf->ppqn; /* XXX: Is this right? */
		pos->beats_per_minute = 60000000.0 / (double)tempo->microseconds_per_quarter_note;

		min = pos->frame / ((double) pos->frame_rate * 60.0);
		abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat;
		abs_beat = abs_tick / pos->ticks_per_beat;

		pos->bar = abs_beat / pos->beats_per_bar;
		pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1;
		pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat);
		pos->bar_start_tick = pos->bar * pos->beats_per_bar * pos->ticks_per_beat;
		pos->bar++; /* adjust start to bar 1 */

		previous_tempo = tempo;

	} else {
		/* Compute BBT info based on previous period. */
		pos->tick += nframes * pos->ticks_per_beat * pos->beats_per_minute / (pos->frame_rate * 60);

		while (pos->tick >= pos->ticks_per_beat) {
			pos->tick -= pos->ticks_per_beat;
			if (++pos->beat > pos->beats_per_bar) {
				pos->beat = 1;
				++pos->bar;
				pos->bar_start_tick += pos->beats_per_bar * pos->ticks_per_beat;
			}
		}
	}
}
Ejemplo n.º 5
0
Archivo: midi.c Proyecto: denemo/denemo
//finds the first note which comes ON after the passed time
DenemoObject *
get_obj_for_start_time (smf_t * smf, gdouble time)
{
  if (time < 0.0)
    time = 0.0;
  static smf_event_t *event;
  smf_event_t *initial = smf_peek_next_event (smf);
  gdouble total = smf_get_length_seconds (smf);
  time = (time > total ? total : time);
  if(smf_seek_to_seconds (smf, time))
    g_debug("smf_seek_to_seconds failed");
  do
    {
      event = smf_get_next_event (smf);
    }
  while (event && (((event->midi_buffer[0] & 0xF0) == MIDI_NOTE_OFF) || !event->user_pointer));
  if (initial && smf_seek_to_event (smf, initial))
      g_debug("smf_seek_to_event failed");  //if (event) g_debug("sought for endObj %f found %f\n", time, event->time_seconds);
  if (event)
    return (DenemoObject *) (event->user_pointer);
  return get_object_for_time (time, TRUE);
}
Ejemplo n.º 6
0
Archivo: smf.c Proyecto: Darko8/libsmf
/**
  * Seeks the SMF to the given position.  For example, after seeking to 1.0 seconds,
  * smf_get_next_event will return first event that happens after the first second of song.
  * \return 0 if everything went ok, nonzero otherwise.
  */
int
smf_seek_to_seconds(smf_t *smf, double seconds)
{
	smf_event_t *event;

	assert(seconds >= 0.0);

	if (seconds == smf->last_seek_position) {
#if 0
		g_debug("Avoiding seek to %f seconds.", seconds);
#endif
		return (0);
	}

	smf_rewind(smf);

#if 0
	g_debug("Seeking to %f seconds.", seconds);
#endif

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

		if (event == NULL) {
			g_critical("Trying to seek past the end of song.");
			return (-1);
		}

		if (event->time_seconds < seconds)
			smf_skip_next_event(smf);
		else
			break;
	}

	smf->last_seek_position = seconds;

	return (0);
}
Ejemplo n.º 7
0
Archivo: midi.c Proyecto: denemo/denemo
//finds the first note which comes OFF after the passed time
DenemoObject *
get_obj_for_end_time (smf_t * smf, gdouble time)
{
  if (time < 0.0)
    time = 0.0;
  static smf_event_t *event = NULL;
  smf_event_t *initial = smf_peek_next_event (smf);
  gdouble total = smf_get_length_seconds (smf);
  time = (time > total ? total : time);
  if(smf_seek_to_seconds (smf, time))
    g_debug("smf_seek_to_seconds failed");
  do
    {
      event = smf_get_next_event (smf);
    }
  while (event && (((event->midi_buffer[0] & 0xF0) == MIDI_NOTE_ON) || !event->user_pointer));
  if (initial && smf_seek_to_event (smf, initial))
      g_debug("smf_seek_to_event failed");//if (event) g_debug("sought for startObj %f found %f\n", time, event->time_seconds);
  if (event)
    return (DenemoObject *) (event->user_pointer);
  //midi is generated by LilyPond, no user_pointer, get timings from events.txt
  return get_object_for_time (time, FALSE);
}
Ejemplo n.º 8
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;
	}
}