most of the 2.X->3.0 commit (up to rev 4299) except for gtk2_ardour/editor_canvas...
[ardour.git] / libs / midi++2 / coremidi_midiport.cc
1 /*
2   Copyright (C) 2004 Paul Davis 
3   Copyright (C) 2004 Grame 
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <fcntl.h>
22 #include <cerrno>
23
24 #include <midi++/coremidi_midiport.h>
25 #include <midi++/types.h>
26 #include <mach/mach_time.h>
27
28 #include <pbd/pthread_utils.h>
29
30 using namespace std;
31 using namespace MIDI;
32
33 MIDITimeStamp CoreMidi_MidiPort::MIDIGetCurrentHostTime()
34 {
35         return mach_absolute_time();
36 }
37
38 CoreMidi_MidiPort::CoreMidi_MidiPort (const XMLNode& node) : Port (node)
39 {
40         Descriptor desc (node);
41
42         firstrecv = true;
43         int err;
44         if (0 == (err = Open(desc))) {
45                 _ok = true;
46         }
47 }
48
49 CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();}
50
51 void CoreMidi_MidiPort::Close ()
52 {
53         if (midi_destination) MIDIEndpointDispose(midi_destination);
54         if (midi_source) MIDIEndpointDispose(midi_source);
55         if (midi_client) MIDIClientDispose(midi_client);
56 }
57
58 int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t ignored)    
59 {
60         OSStatus err;
61         MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer;
62         MIDIPacket* packet = MIDIPacketListInit(pktlist);
63         packet = MIDIPacketListAdd(pktlist,sizeof(midi_buffer),packet,MIDIGetCurrentHostTime(),msglen,msg);
64         
65         if (packet) {
66                 
67                 err = MIDIReceived(midi_source,pktlist);
68                 if (err != noErr) {
69                         //error << "MIDIReceived error" << err << endmsg.
70                 }
71                 
72                 bytes_written += msglen;
73                 return msglen;
74         }else{
75                 return 0;
76         }
77 }
78
79 int CoreMidi_MidiPort::Open (const Descriptor& desc)
80 {
81         OSStatus err;
82         CFStringRef coutputStr;
83         string str;
84         
85         coutputStr = CFStringCreateWithCString(0, desc.device.c_str(), CFStringGetSystemEncoding());
86         err = MIDIClientCreate(coutputStr, 0, 0, &midi_client);
87         CFRelease(coutputStr);
88         if (!midi_client) {
89                 //error << "Cannot open CoreMidi client : " << err << endmsg.
90                 goto error;
91         }
92         
93         str = desc.tag + string("_in");
94         coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
95         err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination);
96         CFRelease(coutputStr);
97         if (!midi_destination) {
98                 //error << "Cannot create CoreMidi destination : " << err << endmsg.
99                 goto error;
100         }
101         
102         str = desc.tag + string("_out");
103         coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
104         err = MIDISourceCreate(midi_client, coutputStr, &midi_source);
105         CFRelease(coutputStr);
106         if (!midi_source) {
107                 //error << "Cannot create CoreMidi source : " << err << endmsg.
108                 goto error;
109         }       
110    
111     return err;
112     
113 error:
114     Close();
115         return err;
116 }
117
118 void CoreMidi_MidiPort::read_proc (const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
119 {
120     CoreMidi_MidiPort* driver = (CoreMidi_MidiPort*)refCon;
121     MIDIPacket *packet = (MIDIPacket *)pktlist->packet; 
122
123     if (driver->firstrecv) {
124             driver->firstrecv = false;
125             PBD::notify_gui_about_thread_creation (pthread_self(), "COREMIDI");
126     }
127
128     for (unsigned int i = 0; i < pktlist->numPackets; ++i) {
129     
130         driver->bytes_read += packet->length;
131                 
132             if (driver->input_parser) {
133                         driver->input_parser->raw_preparse (*driver->input_parser, packet->data, packet->length);
134                         for (int i = 0; i < packet->length; i++) {
135                                 driver->input_parser->scanner (packet->data[i]);
136                         }       
137                         driver->input_parser->raw_postparse (*driver->input_parser, packet->data, packet->length);
138                 }
139                  
140         packet = MIDIPacketNext(packet);
141     }
142 }
143
144 int
145 CoreMidi_MidiPort::discover (vector<PortSet>& ports)
146 {
147         /* XXX do dynamic port discovery here */
148
149         return 0;
150 }