merge with master.
[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 "pbd/xml++.h"
26 #include "pbd/error.h"
27 #include "pbd/failed_constructor.h"
28 #include "pbd/convert.h"
29 #include "pbd/strsplit.h"
30 #include "pbd/stacktrace.h"
31
32 #include "midi++/types.h"
33 #include "midi++/port.h"
34 #include "midi++/channel.h"
35
36 using namespace MIDI;
37 using namespace std;
38 using namespace PBD;
39
40 string Port::state_node_name = "MIDI-port";
41
42 Port::Port (string const & name, Flags flags)
43         : _flags (flags)
44         , _centrally_parsed (true)
45 {
46         init (name, flags);
47 }
48
49 Port::Port (const XMLNode& node)
50         : _centrally_parsed (true)
51 {
52         Descriptor desc (node);
53
54         init (desc.tag, desc.flags);
55
56         /* derived class must call ::set_state() */
57 }
58
59 void
60 Port::init (string const & name, Flags flags)
61 {
62         _ok = false;  /* derived class must set to true if constructor
63                          succeeds.
64                       */
65
66         _parser = 0;
67
68         _tagname = name;
69         _flags = flags;
70
71         _parser = new Parser ();
72
73         for (int i = 0; i < 16; i++) {
74                 _channel[i] = new Channel (i, *this);
75                 _channel[i]->connect_signals ();
76         }
77 }
78
79 Port::~Port ()
80 {
81         for (int i = 0; i < 16; i++) {
82                 delete _channel[i];
83         }
84 }
85
86 /** Send a clock tick message.
87  * \return true on success.
88  */
89 bool
90 Port::clock (timestamp_t timestamp)
91 {
92         static byte clockmsg = 0xf8;
93         
94         if (sends_output()) {
95                 return midimsg (&clockmsg, 1, timestamp);
96         }
97         
98         return false;
99 }
100
101 std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
102 {
103         using namespace std;
104         os << "MIDI::Port { ";
105         os << "name: " << port.name();
106         os << "; ";
107         os << "ok: " << port.ok();
108         os << "; ";
109         os << " }";
110         return os;
111 }
112
113 Port::Descriptor::Descriptor (const XMLNode& node)
114 {
115         const XMLProperty *prop;
116         bool have_tag = false;
117         bool have_mode = false;
118
119         if ((prop = node.property ("tag")) != 0) {
120                 tag = prop->value();
121                 have_tag = true;
122         }
123
124         if ((prop = node.property ("mode")) != 0) {
125
126                 if (strings_equal_ignore_case (prop->value(), "output") || strings_equal_ignore_case (prop->value(), "out")) {
127                         flags = IsOutput;
128                 } else if (strings_equal_ignore_case (prop->value(), "input") || strings_equal_ignore_case (prop->value(), "in")) {
129                         flags = IsInput;
130                 }
131
132                 have_mode = true;
133         }
134
135         if (!have_tag || !have_mode) {
136                 throw failed_constructor();
137         }
138 }
139
140 XMLNode& 
141 Port::get_state () const
142 {
143         XMLNode* root = new XMLNode (state_node_name);
144         root->add_property ("tag", _tagname);
145
146         if (_flags == IsInput) {
147                 root->add_property ("mode", "input");
148         } else {
149                 root->add_property ("mode", "output");
150         }
151         
152 #if 0
153         byte device_inquiry[6];
154
155         device_inquiry[0] = 0xf0;
156         device_inquiry[0] = 0x7e;
157         device_inquiry[0] = 0x7f;
158         device_inquiry[0] = 0x06;
159         device_inquiry[0] = 0x02;
160         device_inquiry[0] = 0xf7;
161         
162         write (device_inquiry, sizeof (device_inquiry), 0);
163 #endif
164
165         return *root;
166 }
167
168 void
169 Port::set_state (const XMLNode& node)
170 {
171         const XMLProperty* prop;
172
173         if ((prop = node.property ("tag")) == 0 || prop->value() != _tagname) {
174                 return;
175         }
176 }
177
178 bool
179 Port::centrally_parsed() const
180 {
181         return _centrally_parsed;
182 }