/* * =================== 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); } }
/* 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(); }
/* 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(); }
/* 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(); }
/* 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(); }
/* 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(); }
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); }
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; }
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; }
/* 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); }
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; }
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; } }
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); }