/* $Id$ */ #include #include #include #include #include #include #include #include "jack.h" Jack::Jack() { m_connected = false; m_client_name = "msplit"; for (int i = 0; i < NUM_CHANNELS; i++) { m_output_map[i] = i; m_active[i] = false; } } Jack::~Jack() { Disconnect(); } bool Jack::Connect() { if (m_connected) return true; jack_status_t status; m_client = jack_client_open(m_client_name, JackNoStartServer, &status); if (m_client == NULL) { if (status & JackServerFailed) { fprintf(stderr, "JACK server not running\n"); } else { fprintf(stderr, "jack_client_open() failed, status = 0x%2.0x\n", status); } return false; } m_connected = true; m_client_name = jack_get_client_name(m_client); jack_on_shutdown(m_client, &ShutdownCallbackHandler, this); jack_set_process_callback(m_client, &ProcessCallbackHandler, this); jack_set_session_callback(m_client, &SessionNotifyCallbackHandler, this); m_input = jack_port_register(m_client, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); for (uint i = 0; i < NUM_CHANNELS; i++) { char port[10]; snprintf(port, sizeof port, "output_%d", i + 1); m_output[i] = jack_port_register(m_client, port, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); } jack_activate(m_client); return true; } void Jack::Disconnect() { if (!m_connected) return; m_connected = false; jack_deactivate(m_client); jack_client_close(m_client); } void Jack::ShutdownCallback() { m_connected = false; } int Jack::ProcessCallback(jack_nframes_t nframes) { void *input = jack_port_get_buffer(m_input, nframes); void *output[NUM_CHANNELS]; for (uint i = 0; i < NUM_CHANNELS; i++) { output[i] = jack_port_get_buffer(m_output[i], nframes); jack_midi_clear_buffer(output[i]); } /* Copy from input to output */ jack_nframes_t event_count = jack_midi_get_event_count(input); jack_nframes_t event_index = 0; for (event_index = 0; event_index < event_count; event_index++) { jack_midi_event_t ev; jack_midi_event_get(&ev, input, event_index); if ((ev.buffer[0] & 0xF0) == 0xF0) { /* Non-channel events, replicate to all outputs */ for (uint i = 0; i < NUM_CHANNELS; i++) { jack_midi_event_write(output[i], ev.time, ev.buffer, ev.size); } } else { int8_t channel = ev.buffer[0] & 0x0F; /* Rewrite the channel */ ev.buffer[0] &= 0xF0; ev.buffer[0] |= m_output_map[channel]; /* Send the event */ jack_midi_event_write(output[channel], ev.time, ev.buffer, ev.size); m_active[channel] = 10; } } return 0; } char *Jack::SessionNotifyCallback(jack_session_event_t code, const char *path, const char *prefix) { switch (code) { case JackSessionQuit: Disconnect(); break; case JackSessionSave: { char filename[PATH_MAX]; snprintf(filename, sizeof filename, "%s%s.msplit", path, prefix); Save(filename); char *response = (char *)malloc(PATH_MAX * 2); snprintf(response, PATH_MAX * 2, "%s -c %s -s %s%s", m_args0, m_client_name, filename, m_ui ? " -u" : ""); return response; } } return NULL; } void Jack::IncChannel(int channel) { assert(channel < NUM_CHANNELS); int &c = m_output_map[channel]; c = (c + 1) % NUM_CHANNELS; } void Jack::DecChannel(int channel) { assert(channel < NUM_CHANNELS); int &c = m_output_map[channel]; c = (c + NUM_CHANNELS - 1) % NUM_CHANNELS; } void Jack::Save(const char *filename) const { FILE *fp = fopen(filename, "w"); for (int channel = 0; channel < NUM_CHANNELS; channel++) { fprintf(fp, "%d\n", m_output_map[channel] + 1); } fclose(fp); } void Jack::Load(const char *filename) { FILE *fp = fopen(filename, "r"); for (int channel = 0; channel < NUM_CHANNELS; channel++) { int output; if (fscanf(fp, "%d", &output) == 1) { m_output_map[channel] = output - 1; } } fclose(fp); }