|
- /*
- Copyright (C) 2009 Grame
- Copyright (C) 2011 Devin Anderson
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
- #include <stdexcept>
-
- #include <mach/mach_time.h>
-
- #include "JackCoreMidiDriver.h"
- #include "JackCoreMidiUtil.h"
- #include "JackEngineControl.h"
-
- using Jack::JackCoreMidiDriver;
-
- ///////////////////////////////////////////////////////////////////////////////
- // Static callbacks
- ///////////////////////////////////////////////////////////////////////////////
-
- void
- JackCoreMidiDriver::HandleInputEvent(const MIDIPacketList *packet_list,
- void *driver, void *port)
- {
- ((JackCoreMidiPhysicalInputPort *) port)->ProcessCoreMidi(packet_list);
- }
-
- void
- JackCoreMidiDriver::HandleNotificationEvent(const MIDINotification *message,
- void *driver)
- {
- ((JackCoreMidiDriver *) driver)->HandleNotification(message);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Class
- ///////////////////////////////////////////////////////////////////////////////
-
- JackCoreMidiDriver::JackCoreMidiDriver(const char *name, const char *alias,
- JackLockedEngine *engine,
- JackSynchro *table):
- JackMidiDriver(name, alias, engine, table)
- {
- mach_timebase_info_data_t info;
- kern_return_t result = mach_timebase_info(&info);
- if (result != KERN_SUCCESS) {
- throw std::runtime_error(mach_error_string(result));
- }
- client = 0;
- fCaptureChannels = 0;
- fPlaybackChannels = 0;
- num_physical_inputs = 0;
- num_physical_outputs = 0;
- num_virtual_inputs = 0;
- num_virtual_outputs = 0;
- physical_input_ports = 0;
- physical_output_ports = 0;
- time_ratio = (((double) info.numer) / info.denom) / 1000.0;
- virtual_input_ports = 0;
- virtual_output_ports = 0;
- }
-
- JackCoreMidiDriver::~JackCoreMidiDriver()
- {}
-
- int
- JackCoreMidiDriver::Attach()
- {
- jack_nframes_t buffer_size = fEngineControl->fBufferSize;
- jack_port_id_t index;
- jack_nframes_t latency = buffer_size;
- jack_latency_range_t latency_range;
- const char *name;
- JackPort *port;
- JackCoreMidiPort *port_obj;
- latency_range.max = latency;
- latency_range.min = latency;
-
- // Physical inputs
- for (int i = 0; i < num_physical_inputs; i++) {
- port_obj = physical_input_ports[i];
- name = port_obj->GetName();
- index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
- JACK_DEFAULT_MIDI_TYPE,
- CaptureDriverFlags, buffer_size);
- if (index == NO_PORT) {
- jack_error("JackCoreMidiDriver::Attach - cannot register physical "
- "input port with name '%s'.", name);
- // X: Do we need to deallocate ports?
- return -1;
- }
- port = fGraphManager->GetPort(index);
- port->SetAlias(port_obj->GetAlias());
- port->SetLatencyRange(JackCaptureLatency, &latency_range);
- fCapturePortList[i] = index;
- }
-
- // Virtual inputs
- for (int i = 0; i < num_virtual_inputs; i++) {
- port_obj = virtual_input_ports[i];
- name = port_obj->GetName();
- index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
- JACK_DEFAULT_MIDI_TYPE,
- CaptureDriverFlags, buffer_size);
- if (index == NO_PORT) {
- jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
- "input port with name '%s'.", name);
- // X: Do we need to deallocate ports?
- return -1;
- }
- port = fGraphManager->GetPort(index);
- port->SetAlias(port_obj->GetAlias());
- port->SetLatencyRange(JackCaptureLatency, &latency_range);
- fCapturePortList[num_physical_inputs + i] = index;
- }
-
- if (! fEngineControl->fSyncMode) {
- latency += buffer_size;
- latency_range.max = latency;
- latency_range.min = latency;
- }
-
- // Physical outputs
- for (int i = 0; i < num_physical_outputs; i++) {
- port_obj = physical_output_ports[i];
- name = port_obj->GetName();
- index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
- JACK_DEFAULT_MIDI_TYPE,
- PlaybackDriverFlags, buffer_size);
- if (index == NO_PORT) {
- jack_error("JackCoreMidiDriver::Attach - cannot register physical "
- "output port with name '%s'.", name);
- // X: Do we need to deallocate ports?
- return -1;
- }
- port = fGraphManager->GetPort(index);
- port->SetAlias(port_obj->GetAlias());
- port->SetLatencyRange(JackPlaybackLatency, &latency_range);
- fPlaybackPortList[i] = index;
- }
-
- // Virtual outputs
- for (int i = 0; i < num_virtual_outputs; i++) {
- port_obj = virtual_output_ports[i];
- name = port_obj->GetName();
- index = fGraphManager->AllocatePort(fClientControl.fRefNum, name,
- JACK_DEFAULT_MIDI_TYPE,
- PlaybackDriverFlags, buffer_size);
- if (index == NO_PORT) {
- jack_error("JackCoreMidiDriver::Attach - cannot register virtual "
- "output port with name '%s'.", name);
- // X: Do we need to deallocate ports?
- return -1;
- }
- port = fGraphManager->GetPort(index);
- port->SetAlias(port_obj->GetAlias());
- port->SetLatencyRange(JackPlaybackLatency, &latency_range);
- fPlaybackPortList[num_physical_outputs + i] = index;
- }
-
- return 0;
- }
-
- int
- JackCoreMidiDriver::Close()
- {
- // Generic MIDI driver close
- int result = JackMidiDriver::Close();
-
- OSStatus status;
- if (physical_input_ports) {
- for (int i = 0; i < num_physical_inputs; i++) {
- delete physical_input_ports[i];
- }
- delete[] physical_input_ports;
- num_physical_inputs = 0;
- physical_input_ports = 0;
- status = MIDIPortDispose(internal_input);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
- status);
- result = -1;
- }
- }
- if (physical_output_ports) {
- for (int i = 0; i < num_physical_outputs; i++) {
- delete physical_output_ports[i];
- }
- delete[] physical_output_ports;
- num_physical_outputs = 0;
- physical_output_ports = 0;
- status = MIDIPortDispose(internal_output);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Close", "MIDIPortDispose",
- status);
- result = -1;
- }
- }
- if (virtual_input_ports) {
- for (int i = 0; i < num_virtual_inputs; i++) {
- delete virtual_input_ports[i];
- }
- delete[] virtual_input_ports;
- num_virtual_inputs = 0;
- virtual_input_ports = 0;
- }
- if (virtual_output_ports) {
- for (int i = 0; i < num_virtual_outputs; i++) {
- delete virtual_output_ports[i];
- }
- delete[] virtual_output_ports;
- num_virtual_outputs = 0;
- virtual_output_ports = 0;
- }
- if (client) {
- status = MIDIClientDispose(client);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientDispose",
- status);
- result = -1;
- }
- client = 0;
- }
- return result;
- }
-
- void
- JackCoreMidiDriver::HandleNotification(const MIDINotification *message)
- {
- // Empty
- }
-
- int
- JackCoreMidiDriver::Open(bool capturing, bool playing, int in_channels,
- int out_channels, bool monitor,
- const char* capture_driver_name,
- const char* playback_driver_name,
- jack_nframes_t capture_latency,
- jack_nframes_t playback_latency)
- {
- int pi_count = 0;
- int po_count = 0;
- int vi_count = 0;
- int vo_count = 0;
- ItemCount potential_po_count;
- ItemCount potential_pi_count;
-
- CFStringRef name = CFStringCreateWithCString(0, "JackMidi",
- CFStringGetSystemEncoding());
- if (! name) {
- jack_error("JackCoreMidiDriver::Open - failed to allocate memory for "
- "client name string");
- return -1;
- }
-
- OSStatus status = MIDIClientCreate(name, HandleNotificationEvent, this,
- &client);
-
- CFRelease(name);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Close", "MIDIClientCreate",
- status);
- return -1;
- }
- char *client_name = fClientControl.fName;
-
- // Allocate and connect physical inputs
- potential_pi_count = MIDIGetNumberOfSources();
- if (potential_pi_count) {
- status = MIDIInputPortCreate(client, CFSTR("Physical Input Port"),
- HandleInputEvent, this, &internal_input);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Open", "MIDIInputPortCreate",
- status);
- goto destroy_virtual_output_ports;
- }
- try {
- physical_input_ports =
- new JackCoreMidiPhysicalInputPort*[potential_pi_count];
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating physical "
- "input port array: %s", e.what());
- goto destroy_internal_input_port;
- }
- for (ItemCount i = 0; i < potential_pi_count; i++) {
- try {
- physical_input_ports[pi_count] =
- new JackCoreMidiPhysicalInputPort(fAliasName, client_name,
- capture_driver_name, i,
- client, internal_input,
- time_ratio);
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating "
- "physical input port: %s", e.what());
- goto destroy_internal_input_port;
- }
- pi_count++;
- }
- }
-
- // Allocate and connect physical outputs
- potential_po_count = MIDIGetNumberOfDestinations();
- if (potential_po_count) {
- status = MIDIOutputPortCreate(client, CFSTR("Physical Output Port"),
- &internal_output);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Open", "MIDIOutputPortCreate",
- status);
- goto destroy_physical_input_ports;
- }
- try {
- physical_output_ports =
- new JackCoreMidiPhysicalOutputPort*[potential_po_count];
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating physical "
- "output port array: %s", e.what());
- goto destroy_internal_output_port;
- }
- for (ItemCount i = 0; i < potential_po_count; i++) {
- try {
- physical_output_ports[po_count] =
- new JackCoreMidiPhysicalOutputPort(fAliasName, client_name,
- playback_driver_name, i,
- client, internal_output,
- time_ratio);
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating "
- "physical output port: %s", e.what());
- goto destroy_internal_output_port;
- }
- po_count++;
- }
- }
-
- // Allocate and connect virtual inputs
- if (in_channels) {
- try {
- virtual_input_ports =
- new JackCoreMidiVirtualInputPort*[in_channels];
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating virtual "
- "input port array: %s", e.what());
- goto destroy_client;
- }
- for (vi_count = 0; vi_count < in_channels; vi_count++) {
- try {
- virtual_input_ports[vi_count] =
- new JackCoreMidiVirtualInputPort(fAliasName, client_name,
- capture_driver_name,
- vi_count + pi_count, client,
- time_ratio);
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating virtual "
- "input port: %s", e.what());
- goto destroy_virtual_input_ports;
- }
- }
- }
-
- // Allocate and connect virtual outputs
- if (out_channels) {
- try {
- virtual_output_ports =
- new JackCoreMidiVirtualOutputPort*[out_channels];
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating virtual "
- "output port array: %s", e.what());
- goto destroy_virtual_input_ports;
- }
- for (vo_count = 0; vo_count < out_channels; vo_count++) {
- try {
- virtual_output_ports[vo_count] =
- new JackCoreMidiVirtualOutputPort(fAliasName, client_name,
- playback_driver_name,
- vo_count + po_count, client,
- time_ratio);
- } catch (std::exception e) {
- jack_error("JackCoreMidiDriver::Open - while creating virtual "
- "output port: %s", e.what());
- goto destroy_virtual_output_ports;
- }
- }
- }
-
-
- if (! (pi_count || po_count || in_channels || out_channels)) {
- jack_error("JackCoreMidiDriver::Open - no CoreMIDI inputs or outputs "
- "found, and no virtual ports allocated.");
- } else if (! JackMidiDriver::Open(capturing, playing,
- in_channels + pi_count,
- out_channels + po_count, monitor,
- capture_driver_name,
- playback_driver_name, capture_latency,
- playback_latency)) {
- num_physical_inputs = pi_count;
- num_physical_outputs = po_count;
- num_virtual_inputs = in_channels;
- num_virtual_outputs = out_channels;
- return 0;
- }
-
- // Cleanup
- if (physical_output_ports) {
- for (int i = 0; i < po_count; i++) {
- delete physical_output_ports[i];
- }
- delete[] physical_output_ports;
- physical_output_ports = 0;
- }
- destroy_internal_output_port:
- status = MIDIPortDispose(internal_output);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
- }
- destroy_physical_input_ports:
- if (physical_input_ports) {
- for (int i = 0; i < pi_count; i++) {
- delete physical_input_ports[i];
- }
- delete[] physical_input_ports;
- physical_input_ports = 0;
- }
- destroy_internal_input_port:
- status = MIDIPortDispose(internal_input);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Open", "MIDIPortDispose", status);
- }
- destroy_virtual_output_ports:
- if (virtual_output_ports) {
- for (int i = 0; i < vo_count; i++) {
- delete virtual_output_ports[i];
- }
- delete[] virtual_output_ports;
- virtual_output_ports = 0;
- }
- destroy_virtual_input_ports:
- if (virtual_input_ports) {
- for (int i = 0; i < vi_count; i++) {
- delete virtual_input_ports[i];
- }
- delete[] virtual_input_ports;
- virtual_input_ports = 0;
- }
- destroy_client:
- status = MIDIClientDispose(client);
- if (status != noErr) {
- WriteMacOSError("JackCoreMidiDriver::Open", "MIDIClientDispose",
- status);
- }
- client = 0;
- return -1;
- }
-
- int
- JackCoreMidiDriver::Read()
- {
- jack_nframes_t buffer_size = fEngineControl->fBufferSize;
- for (int i = 0; i < num_physical_inputs; i++) {
- physical_input_ports[i]->ProcessJack(GetInputBuffer(i), buffer_size);
- }
- for (int i = 0; i < num_virtual_inputs; i++) {
- virtual_input_ports[i]->
- ProcessJack(GetInputBuffer(num_physical_inputs + i), buffer_size);
- }
- return 0;
- }
-
- int
- JackCoreMidiDriver::Start()
- {
- jack_info("JackCoreMidiDriver::Start - Starting driver.");
-
- JackMidiDriver::Start();
-
- int pi_count = 0;
- int po_count = 0;
- int vi_count = 0;
- int vo_count = 0;
-
- jack_info("JackCoreMidiDriver::Start - Enabling physical input ports.");
-
- for (; pi_count < num_physical_inputs; pi_count++) {
- if (physical_input_ports[pi_count]->Start() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
- "input port.");
- goto stop_physical_input_ports;
- }
- }
-
- jack_info("JackCoreMidiDriver::Start - Enabling physical output ports.");
-
- for (; po_count < num_physical_outputs; po_count++) {
- if (physical_output_ports[po_count]->Start() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to enable physical "
- "output port.");
- goto stop_physical_output_ports;
- }
- }
-
- jack_info("JackCoreMidiDriver::Start - Enabling virtual input ports.");
-
- for (; vi_count < num_virtual_inputs; vi_count++) {
- if (virtual_input_ports[vi_count]->Start() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
- "input port.");
- goto stop_virtual_input_ports;
- }
- }
-
- jack_info("JackCoreMidiDriver::Start - Enabling virtual output ports.");
-
- for (; vo_count < num_virtual_outputs; vo_count++) {
- if (virtual_output_ports[vo_count]->Start() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to enable virtual "
- "output port.");
- goto stop_virtual_output_ports;
- }
- }
-
- jack_info("JackCoreMidiDriver::Start - Driver started.");
-
- return 0;
-
- stop_virtual_output_ports:
- for (int i = 0; i < vo_count; i++) {
- if (virtual_output_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
- "output port.");
- }
- }
- stop_virtual_input_ports:
- for (int i = 0; i < vi_count; i++) {
- if (virtual_input_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to disable virtual "
- "input port.");
- }
- }
- stop_physical_output_ports:
- for (int i = 0; i < po_count; i++) {
- if (physical_output_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to disable "
- "physical output port.");
- }
- }
- stop_physical_input_ports:
- for (int i = 0; i < pi_count; i++) {
- if (physical_input_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Start - Failed to disable "
- "physical input port.");
- }
- }
-
- return -1;
- }
-
- int
- JackCoreMidiDriver::Stop()
- {
- int result = 0;
-
- jack_info("JackCoreMidiDriver::Stop - disabling physical input ports.");
-
- for (int i = 0; i < num_physical_inputs; i++) {
- if (physical_input_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
- "input port.");
- result = -1;
- }
- }
-
- jack_info("JackCoreMidiDriver::Stop - disabling physical output ports.");
-
- for (int i = 0; i < num_physical_outputs; i++) {
- if (physical_output_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Stop - Failed to disable physical "
- "output port.");
- result = -1;
- }
- }
-
- jack_info("JackCoreMidiDriver::Stop - disabling virtual input ports.");
-
- for (int i = 0; i < num_virtual_inputs; i++) {
- if (virtual_input_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
- "input port.");
- result = -1;
- }
- }
-
- jack_info("JackCoreMidiDriver::Stop - disabling virtual output ports.");
-
- for (int i = 0; i < num_virtual_outputs; i++) {
- if (virtual_output_ports[i]->Stop() < 0) {
- jack_error("JackCoreMidiDriver::Stop - Failed to disable virtual "
- "output port.");
- result = -1;
- }
- }
-
- return result;
- }
-
- int
- JackCoreMidiDriver::Write()
- {
- jack_nframes_t buffer_size = fEngineControl->fBufferSize;
- for (int i = 0; i < num_physical_outputs; i++) {
- physical_output_ports[i]->ProcessJack(GetOutputBuffer(i), buffer_size);
- }
- for (int i = 0; i < num_virtual_outputs; i++) {
- virtual_output_ports[i]->
- ProcessJack(GetOutputBuffer(num_physical_outputs + i),
- buffer_size);
- }
- return 0;
- }
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- SERVER_EXPORT jack_driver_desc_t * driver_get_descriptor()
- {
- jack_driver_desc_t * desc;
- jack_driver_desc_filler_t filler;
- jack_driver_param_value_t value;
-
- desc = jack_driver_descriptor_construct("coremidi", "Apple CoreMIDI API based MIDI backend", &filler);
-
- value.ui = 0;
- jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
- jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "CoreMIDI virtual bus", NULL);
-
- return desc;
- }
-
- SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
- {
- const JSList * node;
- const jack_driver_param_t * param;
- int virtual_in = 0;
- int virtual_out = 0;
-
- for (node = params; node; node = jack_slist_next (node)) {
- param = (const jack_driver_param_t *) node->data;
-
- switch (param->character) {
-
- case 'i':
- virtual_in = param->value.ui;
- break;
-
- case 'o':
- virtual_out = param->value.ui;
- break;
- }
- }
-
- Jack::JackDriverClientInterface* driver = new Jack::JackCoreMidiDriver("system_midi", "coremidi", engine, table);
- if (driver->Open(1, 1, virtual_in, virtual_out, false, "in", "out", 0, 0) == 0) {
- return driver;
- } else {
- delete driver;
- return NULL;
- }
- }
-
- #ifdef __cplusplus
- }
- #endif
|