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