Merge branch 'master' into audioengine
[ardour.git] / libs / midi++2 / port.cc
1 /*
2     Copyright (C) 1998 Paul Barton-Davis
3     
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id: port.cc 11871 2012-04-10 16:27:01Z paul $
19 */
20 #include <iostream>
21 #include <cstdio>
22 #include <fcntl.h>
23 #include <errno.h>
24
25 #include <jack/jack.h>
26 #include <jack/midiport.h>
27
28 #include "pbd/xml++.h"
29 #include "pbd/error.h"
30 #include "pbd/failed_constructor.h"
31 #include "pbd/convert.h"
32 #include "pbd/strsplit.h"
33 #include "pbd/stacktrace.h"
34
35 #include "midi++/types.h"
36 #include "midi++/port.h"
37 #include "midi++/channel.h"
38
39 using namespace MIDI;
40 using namespace std;
41 using namespace PBD;
42
43 string Port::state_node_name = "MIDI-port";
44
45 Port::Port (string const & name, Flags flags)
46         : _flags (flags)
47         , _centrally_parsed (true)
48 {
49         init (name, flags);
50 }
51
52 Port::Port (const XMLNode& node)
53         : _centrally_parsed (true)
54 {
55         Descriptor desc (node);
56
57         init (desc.tag, desc.flags);
58
59         /* derived class must call ::set_state() */
60 }
61
62 void
63 Port::init (string const & name, Flags flags)
64 {
65         _ok = false;  /* derived class must set to true if constructor
66                          succeeds.
67                       */
68
69         _parser = 0;
70
71         _tagname = name;
72         _flags = flags;
73
74         _parser = new Parser ();
75
76         for (int i = 0; i < 16; i++) {
77                 _channel[i] = new Channel (i, *this);
78                 _channel[i]->connect_signals ();
79         }
80 }
81
82 Port::~Port ()
83 {
84         for (int i = 0; i < 16; i++) {
85                 delete _channel[i];
86         }
87 }
88
89 /** Send a clock tick message.
90  * \return true on success.
91  */
92 bool
93 Port::clock (timestamp_t timestamp)
94 {
95         static byte clockmsg = 0xf8;
96         
97         if (sends_output()) {
98                 return midimsg (&clockmsg, 1, timestamp);
99         }
100         
101         return false;
102 }
103
104 std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
105 {
106         using namespace std;
107         os << "MIDI::Port { ";
108         os << "name: " << port.name();
109         os << "; ";
110         os << "ok: " << port.ok();
111         os << "; ";
112         os << " }";
113         return os;
114 }
115
116 Port::Descriptor::Descriptor (const XMLNode& node)
117 {
118         const XMLProperty *prop;
119         bool have_tag = false;
120         bool have_mode = false;
121
122         if ((prop = node.property ("tag")) != 0) {
123                 tag = prop->value();
124                 have_tag = true;
125         }
126
127         if ((prop = node.property ("mode")) != 0) {
128
129                 if (strings_equal_ignore_case (prop->value(), "output") || strings_equal_ignore_case (prop->value(), "out")) {
130                         flags = IsOutput;
131                 } else if (strings_equal_ignore_case (prop->value(), "input") || strings_equal_ignore_case (prop->value(), "in")) {
132                         flags = IsInput;
133                 }
134
135                 have_mode = true;
136         }
137
138         if (!have_tag || !have_mode) {
139                 throw failed_constructor();
140         }
141 }
142
143 XMLNode& 
144 Port::get_state () const
145 {
146         XMLNode* root = new XMLNode (state_node_name);
147         root->add_property ("tag", _tagname);
148
149         if (_flags == IsInput) {
150                 root->add_property ("mode", "input");
151         } else {
152                 root->add_property ("mode", "output");
153         }
154         
155 #if 0
156         byte device_inquiry[6];
157
158         device_inquiry[0] = 0xf0;
159         device_inquiry[0] = 0x7e;
160         device_inquiry[0] = 0x7f;
161         device_inquiry[0] = 0x06;
162         device_inquiry[0] = 0x02;
163         device_inquiry[0] = 0xf7;
164         
165         write (device_inquiry, sizeof (device_inquiry), 0);
166 #endif
167
168         return *root;
169 }
170
171 void
172 Port::set_state (const XMLNode& node)
173 {
174         const XMLProperty* prop;
175
176         if ((prop = node.property ("tag")) == 0 || prop->value() != _tagname) {
177                 return;
178         }
179 }
180
181 bool
182 Port::centrally_parsed() const
183 {
184         return _centrally_parsed;
185 }