void decode_midi_buffer (uint32_t *buffer_uint32, unsigned int buffer_size_uint32, jack_default_audio_sample_t* buf) { int i; jack_midi_clear_buffer (buf); for (i = 0; i < buffer_size_uint32 - 3;) { uint32_t payload_size; payload_size = buffer_uint32[i]; payload_size = ntohl (payload_size); if (payload_size) { jack_midi_event_t event; event.time = ntohl (buffer_uint32[i+1]); event.size = ntohl (buffer_uint32[i+2]); event.buffer = (jack_midi_data_t*) (&(buffer_uint32[i+3])); jack_midi_event_write (buf, event.time, event.buffer, event.size); // skip to the next event unsigned int nb_data_quads = (((event.size-1) & ~0x3) >> 2)+1; i += 3+nb_data_quads; } else break; // no events can follow an empty event, we're done }
bool MidiBuffer::writeEvent(int sample, MidiData *midiData, size_t dataSize) { if(!isValid()) { return false; } return (jack_midi_event_write( _jackBuffer, (jack_nframes_t)sample, (const jack_midi_data_t *)midiData, dataSize) == 0); }
static void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct process_info* info) { jack_midi_data_t data[MAX_EVENT_SIZE]; stream_t *str = &self->stream[PORT_INPUT]; long size; int64_t alsa_time, time_offset; int64_t frame_offset, event_frame; port_t *port; port = port_get(str->ports, alsa_event->source); if (!port) return; /* * RPNs, NRPNs, Bank Change, etc. need special handling * but seems, ALSA does it for us already. */ snd_midi_event_reset_decode(str->codec); if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) return; // fixup NoteOn with vel 0 if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) { data[0] = 0x80 + (data[0] & 0x0F); data[2] = 0x40; } alsa_time = alsa_event->time.time.tv_sec * NSEC_PER_SEC + alsa_event->time.time.tv_nsec; time_offset = info->alsa_time - alsa_time; frame_offset = (info->sample_rate * time_offset) / NSEC_PER_SEC; event_frame = (int64_t)info->cur_frames - info->period_start - frame_offset + info->nframes; debug_log("input: %d bytes at event_frame = %d", (int)size, (int)event_frame); if (event_frame >= info->nframes && jack_ringbuffer_write_space(port->early_events) >= (sizeof(alsa_midi_event_t) + size)) { alsa_midi_event_t ev; ev.time = event_frame + info->period_start; ev.size = size; jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev)); jack_ringbuffer_write(port->early_events, (char*)data, size); debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes)); return; } if (event_frame < 0) event_frame = 0; else if (event_frame >= info->nframes) event_frame = info->nframes - 1; jack_midi_event_write(port->jack_buf, event_frame, data, size); }
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; }
int process(jack_nframes_t nframes, void *arg) { int j; data *par = (data *) arg; jack_midi_event_t *event = (jack_midi_event_t *) jack_port_get_buffer(par->inPort, nframes); int eCount = jack_midi_get_event_count(event); void *buffer = jack_port_get_buffer(par->outPort, nframes); jack_midi_clear_buffer(buffer); for (eCount, j = 0; eCount > 0; eCount--, j++) { jack_midi_event_t nextE; jack_midi_event_get(&nextE, event, j); // Filtering by channel char ch = nextE.buffer[0] & 0x0F; if (par->channelFilter >= 0) { if (ch != par->channelFilter) return 0; } if (nextE.buffer[0] & 0x80 || nextE.buffer[0] & 0x90) { if (nextE.buffer[1] >= par->currentNote) { nextE.buffer[0] &= 0xF0; nextE.buffer[0] += par->ch2Num; nextE.buffer[1] += par->ch2Shift; } else { nextE.buffer[0] &= 0xF0; nextE.buffer[0] += par->ch1Num; nextE.buffer[1] += par->ch1Shift; } } jack_midi_event_write(buffer, nextE.time, nextE.buffer, nextE.size); } return 0; }
int process(jack_nframes_t nframes, void* arg) { TimerProcess.Start(); static uint64_t frametime = 0; TJackSynth* synth = static_cast<TJackSynth*>(arg); /* Process MIDI input */ void* inbuf = jack_port_get_buffer(MidiIn, nframes); jack_nframes_t event_count = jack_midi_get_event_count(inbuf); for (jack_nframes_t i = 0; i < event_count; i++) { jack_midi_event_t event; jack_midi_event_get(&event, inbuf, i); std::vector<uint8_t> data(event.buffer, event.buffer + event.size); synth->HandleMidi(data, frametime + event.time); } /* Send MIDI */ void* outbuf = jack_port_get_buffer(MidiOut, nframes); jack_midi_clear_buffer(outbuf); while (!MidiOutQueue.empty()) { const std::vector<uint8_t>& data = MidiOutQueue.front(); int ret = jack_midi_event_write(outbuf, 0, data.data(), data.size()); MidiOutQueue.pop(); if (ret != 0) { fprintf(stderr, "MIDI send error\n"); } } synth->Process(nframes); frametime += nframes; TimerProcess.Stop(); return 0; }
void midiSendLong(unsigned char *buf, unsigned long len) { /*int err = snd_rawmidi_write(handle_out, buf, len); if (err != len) { fprintf(stderr, "could not write %ld byte to output, return: %d\n", len, err); exit(1); }*/ if (jack_midi_output_port == NULL) { fprintf(stderr, "midiSendLong failed: output port closed\n"); exit(1); } void* output_buf = jack_port_get_buffer (jack_midi_output_port, 1); jack_midi_clear_buffer(output_buf); printhex("send:", buf, len); int err = jack_midi_event_write(output_buf, 0, buf, len); if (err != 0) { if (err == ENOBUFS) { // if there's not enough space in buffer for event } fprintf(stderr, "could not write %ld byte to output, return: %d\n", len, err); exit(1); } }
static int process_cb(jack_nframes_t nframes, void *arg) { struct cbox_jack_io_impl *jii = arg; struct cbox_io *io = jii->ioi.pio; struct cbox_io_callbacks *cb = io->cb; io->io_env.buffer_size = nframes; for (int i = 0; i < io->io_env.input_count; i++) io->input_buffers[i] = jack_port_get_buffer(jii->inputs[i], nframes); for (int i = 0; i < io->io_env.output_count; i++) { io->output_buffers[i] = jack_port_get_buffer(jii->outputs[i], nframes); if (!io->output_buffers[i]) continue; for (int j = 0; j < nframes; j ++) io->output_buffers[i][j] = 0.f; } for (GSList *p = io->midi_inputs; p; p = p->next) { struct cbox_jack_midi_input *input = p->data; if (input->hdr.output_set || input->hdr.enable_appsink) { copy_midi_data_to_buffer(input->port, io->io_env.buffer_size, &input->hdr.buffer); if (input->hdr.enable_appsink) cbox_midi_appsink_supply(&input->hdr.appsink, &input->hdr.buffer); } else cbox_midi_buffer_clear(&input->hdr.buffer); } if (cb->on_transport_sync) { jack_transport_state_t state = jack_transport_query(jii->client, NULL); if (state != jii->last_transport_state) { jack_position_t pos; jack_transport_query(jii->client, &pos); if (jii->debug_transport) g_message("JACK transport: incoming state change, state = %s, last state = %s, pos = %d\n", transport_state_names[state], transport_state_names[(int)jii->last_transport_state], (int)pos.frame); if (state == JackTransportStopped) { if (cb->on_transport_sync(cb->user_data, ts_stopping, pos.frame)) jii->last_transport_state = state; } else if (state == JackTransportRolling && jii->last_transport_state == JackTransportStarting) { if (cb->on_transport_sync(cb->user_data, ts_rolling, pos.frame)) jii->last_transport_state = state; } else jii->last_transport_state = state; } } cb->process(cb->user_data, io, nframes); for (int i = 0; i < io->io_env.input_count; i++) io->input_buffers[i] = NULL; for (int i = 0; i < io->io_env.output_count; i++) io->output_buffers[i] = NULL; for (GSList *p = io->midi_outputs; p; p = g_slist_next(p)) { struct cbox_jack_midi_output *midiout = p->data; void *pbuf = jack_port_get_buffer(midiout->port, nframes); jack_midi_clear_buffer(pbuf); cbox_midi_merger_render(&midiout->hdr.merger); if (midiout->hdr.buffer.count) { uint8_t tmp_data[4]; for (int i = 0; i < midiout->hdr.buffer.count; i++) { const struct cbox_midi_event *event = cbox_midi_buffer_get_event(&midiout->hdr.buffer, i); const uint8_t *pdata = cbox_midi_event_get_data(event); if ((pdata[0] & 0xF0) == 0x90 && !pdata[2] && event->size == 3) { tmp_data[0] = pdata[0] & ~0x10; tmp_data[1] = pdata[1]; tmp_data[2] = pdata[2]; pdata = tmp_data; } if (jack_midi_event_write(pbuf, event->time, pdata, event->size)) { g_warning("MIDI buffer overflow on JACK output port '%s'", midiout->hdr.name); break; } } } } return 0; }
// rt static int _process(jack_nframes_t nsamples, void *data) { prog_t *handle = data; bin_t *bin = &handle->bin; sp_app_t *app = bin->app; #if defined(JACK_HAS_CYCLE_TIMES) clock_gettime(CLOCK_REALTIME, &handle->ntp); handle->ntp.tv_sec += JAN_1970; // convert NTP to OSC time jack_nframes_t offset = jack_frames_since_cycle_start(handle->client); float T; jack_get_cycle_times(handle->client, &handle->cycle.cur_frames, &handle->cycle.cur_usecs, &handle->cycle.nxt_usecs, &T); (void)T; handle->cycle.ref_frames = handle->cycle.cur_frames + offset; // calculate apparent period double diff = 1e-6 * (handle->cycle.nxt_usecs - handle->cycle.cur_usecs); // calculate apparent samples per period handle->cycle.dT = nsamples / diff; handle->cycle.dTm1 = 1.0 / handle->cycle.dT; #endif // get transport position jack_position_t pos; jack_transport_state_t rolling = jack_transport_query(handle->client, &pos) == JackTransportRolling; int trans_changed = (rolling != handle->trans.rolling) || (pos.frame != handle->trans.frame) || (pos.beats_per_bar != handle->trans.beats_per_bar) || (pos.beat_type != handle->trans.beat_type) || (pos.ticks_per_beat != handle->trans.ticks_per_beat) || (pos.beats_per_minute != handle->trans.beats_per_minute); const size_t sample_buf_size = sizeof(float) * nsamples; const sp_app_system_source_t *sources = sp_app_get_system_sources(app); const sp_app_system_sink_t *sinks = sp_app_get_system_sinks(app); if(sp_app_bypassed(app)) // aka loading state { //fprintf(stderr, "app is bypassed\n"); // clear output buffers for(const sp_app_system_sink_t *sink=sinks; sink->type != SYSTEM_PORT_NONE; sink++) { switch(sink->type) { case SYSTEM_PORT_NONE: case SYSTEM_PORT_CONTROL: case SYSTEM_PORT_COM: break; case SYSTEM_PORT_AUDIO: case SYSTEM_PORT_CV: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); memset(out_buf, 0x0, sample_buf_size); break; } case SYSTEM_PORT_MIDI: case SYSTEM_PORT_OSC: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); jack_midi_clear_buffer(out_buf); break; } } } bin_process_pre(bin, nsamples, true); bin_process_post(bin); return 0; } //TODO use __builtin_assume_aligned // fill input buffers for(const sp_app_system_source_t *source=sources; source->type != SYSTEM_PORT_NONE; source++) { switch(source->type) { case SYSTEM_PORT_NONE: case SYSTEM_PORT_CONTROL: break; case SYSTEM_PORT_AUDIO: case SYSTEM_PORT_CV: { const void *in_buf = jack_port_get_buffer(source->sys_port, nsamples); memcpy(source->buf, in_buf, sample_buf_size); break; } case SYSTEM_PORT_MIDI: { void *in_buf = jack_port_get_buffer(source->sys_port, nsamples); void *seq_in = source->buf; LV2_Atom_Forge *forge = &handle->forge; LV2_Atom_Forge_Frame frame; lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE); LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0); if(ref && trans_changed) ref = _trans_event(handle, forge, rolling, &pos); int n = jack_midi_get_event_count(in_buf); for(int i=0; i<n; i++) { jack_midi_event_t mev; jack_midi_event_get(&mev, in_buf, i); //add jack midi event to in_buf if(ref) ref = lv2_atom_forge_frame_time(forge, mev.time); if(ref) ref = lv2_atom_forge_atom(forge, mev.size, handle->midi_MidiEvent); if(ref) ref = lv2_atom_forge_raw(forge, mev.buffer, mev.size); if(ref) lv2_atom_forge_pad(forge, mev.size); } if(ref) lv2_atom_forge_pop(forge, &frame); else lv2_atom_sequence_clear(seq_in); break; } case SYSTEM_PORT_OSC: { void *in_buf = jack_port_get_buffer(source->sys_port, nsamples); void *seq_in = source->buf; LV2_Atom_Forge *forge = &handle->forge; LV2_Atom_Forge_Frame frame; lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE); LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0); if(ref && trans_changed) ref = _trans_event(handle, forge, rolling, &pos); int n = jack_midi_get_event_count(in_buf); for(int i=0; i<n; i++) { jack_midi_event_t mev; jack_midi_event_get(&mev, (void *)in_buf, i); //add jack osc event to in_buf if(osc_check_packet(mev.buffer, mev.size)) { if(ref) ref = lv2_atom_forge_frame_time(forge, mev.time); handle->ref = ref; osc_dispatch_method(mev.buffer, mev.size, methods, _bundle_in, _bundle_out, handle); ref = handle->ref; } } if(ref) lv2_atom_forge_pop(forge, &frame); else lv2_atom_sequence_clear(seq_in); break; } case SYSTEM_PORT_COM: { void *seq_in = source->buf; LV2_Atom_Forge *forge = &handle->forge; LV2_Atom_Forge_Frame frame; lv2_atom_forge_set_buffer(forge, seq_in, SEQ_SIZE); LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(forge, &frame, 0); const LV2_Atom_Object *obj; size_t size; while((obj = varchunk_read_request(bin->app_from_com, &size))) { if(ref) ref = lv2_atom_forge_frame_time(forge, 0); if(ref) ref = lv2_atom_forge_raw(forge, obj, size); if(ref) lv2_atom_forge_pad(forge, size); varchunk_read_advance(bin->app_from_com); } if(ref) lv2_atom_forge_pop(forge, &frame); else lv2_atom_sequence_clear(seq_in); break; } } } // update transport state handle->trans.rolling = rolling; handle->trans.frame = rolling ? handle->trans.frame + nsamples : pos.frame; handle->trans.beats_per_bar = pos.beats_per_bar; handle->trans.beat_type = pos.beat_type; handle->trans.ticks_per_beat = pos.ticks_per_beat; handle->trans.beats_per_minute = pos.beats_per_minute; bin_process_pre(bin, nsamples, false); // fill output buffers for(const sp_app_system_sink_t *sink=sinks; sink->type != SYSTEM_PORT_NONE; sink++) { switch(sink->type) { case SYSTEM_PORT_NONE: case SYSTEM_PORT_CONTROL: break; case SYSTEM_PORT_AUDIO: case SYSTEM_PORT_CV: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); memcpy(out_buf, sink->buf, sample_buf_size); break; } case SYSTEM_PORT_MIDI: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); const LV2_Atom_Sequence *seq_out = sink->buf; // fill midi output buffer jack_midi_clear_buffer(out_buf); if(seq_out) { LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev) { const LV2_Atom *atom = &ev->body; if(atom->type != handle->midi_MidiEvent) continue; // ignore non-MIDI events jack_midi_event_write(out_buf, ev->time.frames, LV2_ATOM_BODY_CONST(atom), atom->size); } } break; } case SYSTEM_PORT_OSC: { void *out_buf = jack_port_get_buffer(sink->sys_port, nsamples); const LV2_Atom_Sequence *seq_out = sink->buf; // fill midi output buffer jack_midi_clear_buffer(out_buf); if(seq_out) { LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev) { const LV2_Atom_Object *obj = (const LV2_Atom_Object *)&ev->body; handle->osc_ptr = handle->osc_buf; handle->osc_end = handle->osc_buf + OSC_SIZE; osc_atom_event_unroll(&handle->oforge, obj, _bundle_push_cb, _bundle_pop_cb, _message_cb, handle); size_t size = handle->osc_ptr ? handle->osc_ptr - handle->osc_buf : 0; if(size) { jack_midi_event_write(out_buf, ev->time.frames, handle->osc_buf, size); } } } break; } case SYSTEM_PORT_COM: { const LV2_Atom_Sequence *seq_out = sink->buf; LV2_ATOM_SEQUENCE_FOREACH(seq_out, ev) { const LV2_Atom *atom = (const LV2_Atom *)&ev->body; // try do process events directly bin->advance_ui = sp_app_from_ui(bin->app, atom); if(!bin->advance_ui) // queue event in ringbuffer instead { //fprintf(stderr, "plugin ui direct is blocked\n"); void *ptr; size_t size = lv2_atom_total_size(atom); if((ptr = varchunk_write_request(bin->app_from_app, size))) { memcpy(ptr, atom, size); varchunk_write_advance(bin->app_from_app, size); } else { //fprintf(stderr, "app_from_ui ringbuffer full\n"); //FIXME } } } break; } } } bin_process_post(bin); return 0; }
void ModeHandler::process(const jack_nframes_t nframes) { void* inPortBuf = jack_port_get_buffer(m_inputPort, nframes); void* outPortBuf = jack_port_get_buffer(m_outputPort, nframes); jack_midi_clear_buffer(outPortBuf); const jack_transport_state_t state = jack_transport_query(m_client, nullptr); const jack_nframes_t eventCount = jack_midi_get_event_count(inPortBuf); for (size_t i = 0; i < eventCount; ++i) { jack_midi_event_t inEvent; jack_midi_event_get(&inEvent, inPortBuf, i); const jack_midi_data_t cmd = inEvent.buffer[0] & 0xf0; switch (cmd) { case MIDI_NOTEON: case MIDI_NOTEOFF: { const jack_midi_data_t note = inEvent.buffer[1]; const jack_midi_data_t velocity = inEvent.buffer[2]; int noteToUse = note; // we only map on a note on // on a note off we use the previously mapped note // and only is transport is rolling if (cmd == MIDI_NOTEON && velocity > 0) { if (state == JackTransportRolling) { const int newNote = transpose(m_offset, m_quirkOffset, note); m_mappedNotes[note] = newNote; noteToUse = newNote; } } else { // NOTEOFF if (m_mappedNotes[note] != NOT_MAPPED) { noteToUse = m_mappedNotes[note]; m_mappedNotes[note] = NOT_MAPPED; } } if (noteToUse != SKIP) { jack_midi_data_t data[3]; data[0] = inEvent.buffer[0]; data[1] = noteToUse;; data[2] = inEvent.buffer[2]; jack_midi_event_write(outPortBuf, inEvent.time, data, 3); } break; } default: { // just forward everything else jack_midi_event_write(outPortBuf, inEvent.time, inEvent.buffer, inEvent.size); } } } }