Beispiel #1
0
/*
 * =================== Input/output port handling =========================
 */
static
void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir, jack_nframes_t nframes)
{
	const snd_seq_real_time_t* alsa_time;
	snd_seq_queue_status_t *status;

	snd_seq_queue_status_alloca(&status);

	info->dir = dir;

	info->period_start = jack_last_frame_time(self->jack);
	info->nframes = nframes;
	info->sample_rate = jack_get_sample_rate(self->jack);

	info->cur_frames = jack_frame_time(self->jack);

	// immediately get alsa'a real time (uhh, why everybody has their own 'real' time)
	snd_seq_get_queue_status(self->seq, self->queue, status);
	alsa_time = snd_seq_queue_status_get_real_time(status);
	info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec;

	if (info->period_start + info->nframes < info->cur_frames) {
		int periods_lost = (info->cur_frames - info->period_start) / info->nframes;
		info->period_start += periods_lost * info->nframes;
		debug_log("xrun detected: %d periods lost\n", periods_lost);
	}
}
Beispiel #2
0
/* queue a note-off event by patch id */
void mixer_note_off_with_id(int id, int note)
{
    writer->type = MIXER_NOTEOFF_WITH_ID;
    writer->ticks = jack_last_frame_time(jc);
    writer->id_note.id = id;
    writer->id_note.note = note;
    advance_writer();
}
Beispiel #3
0
/* queue a note-off event */
void mixer_note_off(int chan, int note)
{
    writer->type = MIXER_NOTEOFF;
    writer->ticks = jack_last_frame_time(jc);
    writer->note.chan = chan;
    writer->note.note = note;
    advance_writer();
}
Beispiel #4
0
/* queue control change event */
void mixer_control(int chan, int param, float value)
{
    writer->type = MIXER_CONTROL;
    writer->ticks = jack_last_frame_time(jc);
    writer->control.chan = chan;
    writer->control.param = param;
    writer->control.value = value;
    advance_writer();
}
Beispiel #5
0
/* queue a note-on event by patch id */
void mixer_note_on_with_id(int id, int note, float vel)
{
    writer->type = MIXER_NOTEON_WITH_ID;
    writer->ticks = jack_last_frame_time(jc);
    writer->id_note.id = id;
    writer->id_note.note = note;
    writer->id_note.vel = vel;
    advance_writer();
}
Beispiel #6
0
/* queue a note-on event */
void mixer_note_on(int chan, int note, float vel)
{
    writer->type = MIXER_NOTEON;
    writer->ticks = jack_last_frame_time(jc);
    writer->note.chan = chan;
    writer->note.note = note;
    writer->note.vel = vel;
    advance_writer();
}
Beispiel #7
0
static
void jack_process(midi_stream_t *str, jack_nframes_t nframes)
{
    int r, w;
    process_jack_t proc;
    jack_nframes_t cur_frames;

    if (!str->owner->keep_walking)
        return;

    proc.midi = str->owner;
    proc.nframes = nframes;
    proc.frame_time = jack_last_frame_time(proc.midi->client);
    cur_frames = jack_frame_time(proc.midi->client);
    int periods_diff = cur_frames - proc.frame_time;
    if (periods_diff < proc.nframes) {
        int periods_lost = periods_diff / proc.nframes;
        proc.frame_time += periods_lost * proc.nframes;
        debug_log("xrun detected: %d periods lost", periods_lost);
    }

    // process existing ports
    for (r=0, w=0; r<str->jack.nports; ++r) {
        midi_port_t *port = str->jack.ports[r];
        proc.port = port;

        assert (port->state > PORT_ADDED_TO_JACK && port->state < PORT_REMOVED_FROM_JACK);

        proc.buffer = jack_port_get_buffer(port->jack, nframes);
        if (str->mode == POLLIN)
            jack_midi_clear_buffer(proc.buffer);

        if (port->state == PORT_REMOVED_FROM_MIDI) {
            port->state = PORT_REMOVED_FROM_JACK; // this signals to scan thread
            continue; // this effectively removes port from the midi->in.jack.ports[]
        }

        (str->process_jack)(&proc);

        if (r != w)
            str->jack.ports[w] = port;
        ++w;
    }
    if (str->jack.nports != w)
        debug_log("jack_%s: nports %d -> %d", str->name, str->jack.nports, w);
    str->jack.nports = w;

    jack_add_ports(str); // it makes no sense to add them earlier since they have no data yet

    // wake midi thread
    write(str->wake_pipe[1], &r, 1);
}
Beispiel #8
0
    void PlayerHandler::process(const jack_nframes_t nframes)
    {
      void* outPortBuf = jack_port_get_buffer(m_outputPort, nframes);

      jack_midi_clear_buffer(outPortBuf);

      jack_position_t pos;
      const jack_transport_state_t state = jack_transport_query(m_client, &pos);

      switch (state)
      {
      case JackTransportStopped:
	{
	  if (m_previousState != state)
	  {
	    // stop them all now
	    allNotesOff(outPortBuf, 0);
	    // reset position
	    m_position = 0;
	  }
	  break;
	}
      case JackTransportRolling:
	{
	  const jack_nframes_t framesAtStart = jack_last_frame_time(m_client);
	  const jack_nframes_t lastFrame = framesAtStart + nframes;

	  const jack_nframes_t startFrame = framesAtStart - pos.frame;

	  while (m_position < m_master.size() && startFrame + m_master[m_position].m_time >= framesAtStart && startFrame + m_master[m_position].m_time < lastFrame)
	  {
	    const MidiEvent & event = m_master[m_position];
	    const jack_nframes_t newOffset = event.m_time - pos.frame;
	    jack_midi_event_write(outPortBuf, newOffset, event.m_data, event.m_size);
	    noteChange(event.m_data);

	    ++m_position;
	  }
	  break;
	}
      default:
	{
	  break;
	}
      }

      m_previousState = state;
    }
Beispiel #9
0
static int
a2j_process (jack_nframes_t nframes, void * arg)
{
	struct a2j* self = (struct a2j *) arg;
	struct a2j_stream * stream_ptr;
	int i;
	struct a2j_port ** port_ptr;
	struct a2j_port * port;

	if (g_freewheeling) {
		return 0;
	}

	self->cycle_start = jack_last_frame_time (self->jack_client);
	
	stream_ptr = &self->stream;
	a2j_add_ports (stream_ptr);
	
	// process ports
	
	for (i = 0 ; i < PORT_HASH_SIZE ; i++) {

		port_ptr = &stream_ptr->port_hash[i];

		while (*port_ptr != NULL) {

			struct a2j_alsa_midi_event ev;
			jack_nframes_t now;
			jack_nframes_t one_period;
			char *ev_buf;
				
			port = *port_ptr;
			
			if (port->is_dead) {
				if (jack_ringbuffer_write_space (self->port_del) >= sizeof(port_ptr)) {
				
					a2j_debug("jack: removed port %s", port->name);
					*port_ptr = port->next;
					jack_ringbuffer_write (self->port_del, (char*)&port, sizeof(port));
				} else {
					a2j_error ("port deletion lost - no space in event buffer!");
				}

				port_ptr = &port->next;
				continue;
			}

			port->jack_buf = jack_port_get_buffer(port->jack_port, nframes);
				
			/* grab data queued by the ALSA input thread and write it into the JACK
			   port buffer. it will delivered during the JACK period that this
			   function is called from.
			*/
				
			/* first clear the JACK port buffer in preparation for new data 
			 */
				
			// a2j_debug ("PORT: %s process input", jack_port_name (port->jack_port));
				
			jack_midi_clear_buffer (port->jack_buf);
				
			now = jack_frame_time (self->jack_client);
			one_period = jack_get_buffer_size (self->jack_client);
				
			while (jack_ringbuffer_peek (port->inbound_events, (char*)&ev, sizeof(ev) ) == sizeof(ev) ) {
					
				jack_midi_data_t* buf;
				jack_nframes_t offset;
					
				if (ev.time >= self->cycle_start) {
					break;
				}
					
				//jack_ringbuffer_read_advance (port->inbound_events, sizeof (ev));
				ev_buf = (char *) alloca( sizeof(ev) + ev.size );
					
				if (jack_ringbuffer_peek (port->inbound_events, ev_buf, sizeof(ev) + ev.size ) != sizeof(ev) + ev.size)
					break;
					
				offset = self->cycle_start - ev.time;
				if (offset > one_period) {
					/* from a previous cycle, somehow. cram it in at the front */
					offset = 0;
				} else {
					/* offset from start of the current cycle */
					offset = one_period - offset;
				}
					
				a2j_debug ("event at %d offset %d", ev.time, offset);
					
				/* make sure there is space for it */
					
				buf = jack_midi_event_reserve (port->jack_buf, offset, ev.size);
					
				if (buf) {
					/* grab the event */
					memcpy( buf, ev_buf + sizeof(ev), ev.size );
				} else {
					/* throw it away (no space) */
					a2j_error ("threw away MIDI event - not reserved at time %d", ev.time);
				}
				jack_ringbuffer_read_advance (port->inbound_events, sizeof(ev) + ev.size);
					
				a2j_debug("input on %s: sucked %d bytes from inbound at %d", jack_port_name (port->jack_port), ev.size, ev.time);
			}
			
			port_ptr = &port->next;
		}
	}

	return 0;
}
Beispiel #10
0
/* mix current soundscape into buf */
void mixer_mixdown(float *buf, int frames)
{
    Tick curticks = jack_last_frame_time(jc);
    Event* event = NULL;
    int wrote = 0;
    int write;
    int i;
    int d = 0;
    float logvol = 0.0;

    for (i = 0; i < frames * 2; i++)
        buf[i] = 0.0;

    /* adjust the ticks in the direct events */
    for (i = 0; i < direct_events_end; ++i)
         direct_events[i].ticks += curticks - frames;

    /* get the first event */
    if (reader != writer)
    {
        if (d < direct_events_end
         && direct_events[d].ticks < reader->ticks)
        {
            event = &direct_events[d++];
        }
        else
        {
            event = reader;
            advance_reader();
        }
    }
    else if (d < direct_events_end)
        event = &direct_events[d++];


    /* process events */
    while (event)
    {
        if (event->ticks > curticks)
            break;

        write = event->ticks - (curticks - frames + wrote);

        if (write > 0)
        {
            patch_render(buf + wrote*2, write);
            wrote += write;
        }

        switch (event->type)
        {
        case MIXER_NOTEON:
            patch_trigger(  event->note.chan,
                            event->note.note,
                            event->note.vel,
                            event->ticks);
            break;

        case MIXER_NOTEON_WITH_ID:
            patch_trigger_with_id(  event->id_note.id,
                                    event->id_note.note,
                                    event->id_note.vel,
                                    event->ticks);
            break;

        case MIXER_NOTEOFF:
            patch_release(event->note.chan, event->note.note);
            break;

        case MIXER_NOTEOFF_WITH_ID:
            patch_release_with_id(event->id_note.id, event->id_note.note);
            break;

        case MIXER_CONTROL:
            patch_control(  event->control.chan,
                            event->control.param,
                            event->control.value);
            break;

        case MIXER_PITCH_BEND:
            patch_control(  event->control.chan,
                            CC_PITCH_WHEEL,
                            event->control.value);
            break;

        default:
            break;
        }

        /* get next event */
        if (reader != writer)
        {
            if (d < direct_events_end
             && direct_events[d].ticks < reader->ticks)
            {
                event = &direct_events[d++];
            }
            else
            {
                event = reader;
                advance_reader();
            }
        }
        else if (d < direct_events_end)
            event = &direct_events[d++];
        else
            event = NULL;
    }

    /* reset the direct event buffer */
    direct_events_end = 0;

    if (wrote < frames)
        patch_render(buf + wrote*2, frames - wrote);

    preview_render(buf, frames);

    /* scale to master amplitude */
    logvol = log_amplitude(amplitude);

    for (i = 0; i < frames * 2; i++)
        buf[i] *= logvol;
}
    uint32_t JackAudioSystem::segment_start_time_stamp()
    {
	if( !_client ) return 0;
	return jack_last_frame_time(_client);
    }
Beispiel #12
0
static int
handle_process(jack_nframes_t frames, void *arg)
{
    jack_midi_data_t *buffer;
    jack_midi_event_t event;
    jack_nframes_t event_count;
    jack_nframes_t event_time;
    jack_nframes_t frame;
    size_t i;
    jack_nframes_t last_frame_time;
    jack_midi_data_t *message;
    jack_time_t microseconds;
    void *port_buffer;
    jack_time_t time;
    jack_midi_clear_buffer(jack_port_get_buffer(out_port, frames));
    switch (process_state) {

    case 0:
        /* State: initializing */
        switch (wait_semaphore(init_semaphore, 0)) {
        case -1:
            set_process_error(SOURCE_WAIT_SEMAPHORE, get_semaphore_error());
            /* Fallthrough on purpose */
        case 0:
            return 0;
        }
        highest_latency = 0;
        lowest_latency = 0;
        messages_received = 0;
        messages_sent = 0;
        process_state = 1;
        total_latency = 0;
        total_latency_time = 0;
        unexpected_messages = 0;
        xrun_count = 0;
        jack_port_get_latency_range(remote_in_port, JackCaptureLatency,
                                    &in_latency_range);
        jack_port_get_latency_range(remote_out_port, JackPlaybackLatency,
                                    &out_latency_range);
        goto send_message;

    case 1:
        /* State: processing */
        port_buffer = jack_port_get_buffer(in_port, frames);
        event_count = jack_midi_get_event_count(port_buffer);
        last_frame_time = jack_last_frame_time(client);
        for (i = 0; i < event_count; i++) {
            jack_midi_event_get(&event, port_buffer, i);
            message = (messages_received % 2) ? message_2 : message_1;
            if ((event.size == message_size) &&
                (! memcmp(message, event.buffer,
                          message_size * sizeof(jack_midi_data_t)))) {
                goto found_message;
            }
            unexpected_messages++;
        }
        microseconds = jack_frames_to_time(client, last_frame_time) -
            last_activity_time;
        if ((microseconds / 1000000) >= timeout) {
            set_process_error(SOURCE_PROCESS, ERROR_MSG_TIMEOUT);
        }
        break;
    found_message:
        event_time = last_frame_time + event.time;
        frame = event_time - last_activity;
        time = jack_frames_to_time(client, event_time) - last_activity_time;
        if ((! highest_latency) || (frame > highest_latency)) {
            highest_latency = frame;
            highest_latency_time = time;
        }
        if ((! lowest_latency) || (frame < lowest_latency)) {
            lowest_latency = frame;
            lowest_latency_time = time;
        }
        latency_time_values[messages_received] = time;
        latency_values[messages_received] = frame;
        total_latency += frame;
        total_latency_time += time;
        messages_received++;
        if (messages_received == samples) {
            process_state = 2;
            if (! signal_semaphore(process_semaphore)) {
                /* Sigh ... */
                die(SOURCE_SIGNAL_SEMAPHORE, get_semaphore_error());
            }
            break;
        }
    send_message:
        frame = (jack_nframes_t) ((((double) rand()) / RAND_MAX) * frames);
        if (frame >= frames) {
            frame = frames - 1;
        }
        port_buffer = jack_port_get_buffer(out_port, frames);
        buffer = jack_midi_event_reserve(port_buffer, frame, message_size);
        if (buffer == NULL) {
            set_process_error(SOURCE_EVENT_RESERVE, ERROR_RESERVE);
            break;
        }
        message = (messages_sent % 2) ? message_2 : message_1;
        memcpy(buffer, message, message_size * sizeof(jack_midi_data_t));
        last_activity = jack_last_frame_time(client) + frame;
        last_activity_time = jack_frames_to_time(client, last_activity);
        messages_sent++;

    case 2:
        /* State: finished - do nothing */
    case -1:
        /* State: error - do nothing */
    case -2:
        /* State: signalled - do nothing */
        ;
    }
    return 0;
}
void
process_midi_input (jack_nframes_t nframes)
{
   static int time_of_first_event = -1;
   int /*read,*/ events, i, channel;
   jack_midi_event_t event;
   int last_frame_time = jack_last_frame_time(jack_client);
   void * port_buffer = jack_port_get_buffer(input_port, nframes);
   if (port_buffer == NULL)
   {
      warn_from_jack_thread_context
      (
         "jack_port_get_buffer failed, cannot receive anything."
      );
      return;
   }

#ifdef JACK_MIDI_NEEDS_NFRAMES
   events = jack_midi_get_event_count(port_buffer, nframes);
#else
   events = jack_midi_get_event_count(port_buffer);
#endif

   for (i = 0; i < events; ++i)
   {
      smf_event_t * smf_event;

#ifdef JACK_MIDI_NEEDS_NFRAMES
      int read = jack_midi_event_get(&event, port_buffer, i, nframes);
#else
      int read = jack_midi_event_get(&event, port_buffer, i);
#endif
      if (read) {
         warn_from_jack_thread_context("jack_midi_event_get failed, RECEIVED NOTE LOST.");
         continue;
      }
      if (event.buffer[0] >= 0xF8)              /* Ignore realtime messages. */
         continue;

      if (time_of_first_event == -1)            /* First event received? */
         time_of_first_event = last_frame_time + event.time;

      smf_event = smf_event_new_from_pointer(event.buffer, event.size);
      if (smf_event == NULL)
      {
         warn_from_jack_thread_context
         (
            "smf_event_from_pointer failed, RECEIVED NOTE LOST."
         );
         continue;
      }
//    assert(smf_event->midi_buffer_length >= 1);
      channel = smf_event->midi_buffer[0] & 0x0F;
      smf_track_add_event_seconds
      (
         tracks[channel], smf_event,
         nframes_to_seconds
         (
            jack_last_frame_time(jack_client) + event.time - time_of_first_event
         )
      );
   }
}
// JACK specifics.
int qmidinetJackMidiDevice::process ( jack_nframes_t nframes )
{
	jack_nframes_t buffer_size = jack_get_buffer_size(m_pJackClient);

	m_last_frame_time  = jack_last_frame_time(m_pJackClient);

	// Enqueue/dequeue events
	// to/from ring-buffers...
	for (int i = 0; i < m_nports; ++i) {

		if (m_ppJackPortIn && m_ppJackPortIn[i] && m_pJackBufferIn) {
			void *pvBufferIn
				= jack_port_get_buffer(m_ppJackPortIn[i], nframes);
			const int nevents = jack_midi_get_event_count(pvBufferIn);
			const unsigned int nlimit
				= jack_ringbuffer_write_space(m_pJackBufferIn);
			unsigned char  achBuffer[nlimit];
			unsigned char *pchBuffer = &achBuffer[0];
			unsigned int nwrite = 0;
			for (int n = 0; n < nevents; ++n) {
				if (nwrite + sizeof(qmidinetJackMidiEvent) >= nlimit)
					break;
				qmidinetJackMidiEvent *pJackEventIn
					= (struct qmidinetJackMidiEvent *) pchBuffer;
				jack_midi_event_get(&pJackEventIn->event, pvBufferIn, n);
				if (nwrite + sizeof(qmidinetJackMidiEvent)
					+ pJackEventIn->event.size >= nlimit)
					break;
				pJackEventIn->port = i;
				pchBuffer += sizeof(qmidinetJackMidiEvent);
				nwrite += sizeof(qmidinetJackMidiEvent);
				::memcpy(pchBuffer,
					pJackEventIn->event.buffer, pJackEventIn->event.size);
				pchBuffer += pJackEventIn->event.size;
				nwrite += pJackEventIn->event.size;
			}
			if (nwrite > 0) {
				jack_ringbuffer_write(m_pJackBufferIn,
					(const char *) achBuffer, nwrite);
			}
		}
	
		if (m_ppJackPortOut && m_ppJackPortOut[i] && m_pJackBufferOut) {
			void *pvBufferOut
				= jack_port_get_buffer(m_ppJackPortOut[i], nframes);
			jack_midi_clear_buffer(pvBufferOut);
			const unsigned int nlimit
				= jack_midi_max_event_size(pvBufferOut);
			unsigned int nread = 0;
			qmidinetJackMidiEvent ev;
			while (jack_ringbuffer_peek(m_pJackBufferOut,
					(char *) &ev, sizeof(ev)) == sizeof(ev)
					&& nread < nlimit) {
				if (ev.port != i)
					break;
				if (ev.event.time > m_last_frame_time)
					break;
				jack_nframes_t offset = m_last_frame_time - ev.event.time;
				if (offset > buffer_size)
					offset = 0;
				else
					offset = buffer_size - offset;
				jack_ringbuffer_read_advance(m_pJackBufferOut, sizeof(ev));
				jack_midi_data_t *pMidiData
					= jack_midi_event_reserve(pvBufferOut, offset, ev.event.size);
				if (pMidiData)
					jack_ringbuffer_read(m_pJackBufferOut,
						(char *) pMidiData, ev.event.size);
				else
				jack_ringbuffer_read_advance(m_pJackBufferOut, ev.event.size);
				nread += ev.event.size;
			}
		}
	}

	if (m_pJackBufferIn
		&& jack_ringbuffer_read_space(m_pJackBufferIn) > 0)
		m_pRecvThread->sync();

	return 0;
}
Beispiel #15
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;
	}
}
Beispiel #16
0
jack_nframes_t luajack_last_frame_time(luajack_t *client) 
	{
	cud_t *cud = get_cud(client);	
	if(!cud) return 0;
	return jack_last_frame_time(cud->client);
	}