xref: /haiku/src/servers/midi/PortDrivers.cpp (revision d5cd5d63ff0ad395989db6cf4841a64d5b545d1d)
1 /*
2  * Copyright (c) 2003 Matthijs Hollemans
3  * Copyright (c) 2003 Jerome Leveque
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 
28 #include "PortDrivers.h"
29 
30 //------------------------------------------------------------------------------
31 
32 MidiPortConsumer::MidiPortConsumer(int fd_, const char* name = NULL)
33 	: BMidiLocalConsumer(name)
34 {
35 	fd = fd_;
36 }
37 
38 //------------------------------------------------------------------------------
39 
40 void MidiPortConsumer::Data(
41 	uchar* data, size_t length, bool atomic, bigtime_t time)
42 {
43 	snooze_until(time - Latency(), B_SYSTEM_TIMEBASE);
44 
45 	if (write(fd, data, length) == -1)
46 	{
47 		perror("Error sending data to driver");
48 	}
49 }
50 
51 //------------------------------------------------------------------------------
52 
53 MidiPortProducer::MidiPortProducer(int fd_, const char *name = NULL)
54 	: BMidiLocalProducer(name)
55 {
56 	fd = fd_;
57 	keepRunning = true;
58 
59 	thread_id thread = spawn_thread(
60 		SpawnThread, "MidiDriversProducer", B_URGENT_PRIORITY, this);
61 
62 	resume_thread(thread);
63 }
64 
65 //------------------------------------------------------------------------------
66 
67 MidiPortProducer::~MidiPortProducer()
68 {
69 	keepRunning = false;
70 }
71 
72 //------------------------------------------------------------------------------
73 
74 int32 MidiPortProducer::SpawnThread(void* data)
75 {
76 	return ((MidiPortProducer*) data)->GetData();
77 }
78 
79 //------------------------------------------------------------------------------
80 
81 int32 MidiPortProducer::GetData()
82 {
83 	uchar data[3];
84 
85 	while (keepRunning)
86 	{
87 		if (read(fd, data, 1) != 1)
88 		{
89 			perror("Error reading data from driver");
90 			return B_ERROR;
91 		}
92 
93 		switch (data[0] & 0xF0)
94 		{
95 			case B_NOTE_OFF:
96 				read(fd, data + 1, 2);
97 				SprayNoteOff(data[0] & 0x0F, data[1], data[2]);
98 				break;
99 
100 			case B_NOTE_ON:
101 				read(fd, data + 1, 2);
102 				SprayNoteOn(data[0] & 0x0F, data[1], data[2]);
103 				break;
104 
105 			case B_KEY_PRESSURE:
106 				read(fd, data + 1, 2);
107 				SprayKeyPressure(data[0] & 0x0F, data[1], data[2]);
108 				break;
109 
110 			case B_CONTROL_CHANGE:
111 				read(fd, data + 1, 2);
112 				SprayControlChange(data[0] & 0x0F, data[1], data[2]);
113 				break;
114 
115 			case B_PROGRAM_CHANGE:
116 				read(fd, data + 1, 1);
117 				SprayProgramChange(data[0] & 0x0F, data[1]);
118 				break;
119 
120 			case B_CHANNEL_PRESSURE:
121 				read(fd, data + 1, 1);
122 				SprayChannelPressure(data[0] & 0x0F, data[1]);
123 				break;
124 
125 			case B_PITCH_BEND:
126 				read(fd, data + 1, 2);
127 				SprayPitchBend(data[0] & 0x0F, data[1], data[2]);
128 				break;
129 		}
130 
131 		switch (data[0])
132 		{
133 			case B_SYS_EX_START:
134 			{
135 				size_t msg_size = 4096;
136 				uchar* msg = (uchar*) malloc(msg_size);
137 				size_t count = 0;
138 
139 				while (read(fd, msg + count, 1) == 1)
140 				{
141 					// Realtime events may interleave System Exclusives. Any
142 					// non-realtime status byte (not just 0xF7) ends a sysex.
143 
144 					if (msg[count] >= 0xF8)
145 					{
146 						SpraySystemRealTime(msg[count]);
147 					}
148 					else if (msg[count] >= 0xF0)
149 					{
150 						SpraySystemExclusive(msg, count - 1);
151 						break;
152 					}
153 					else  // a normal data byte
154 					{
155 						++count;
156 						if (count == msg_size)
157 						{
158 							msg_size *= 2;
159 							msg = (uchar*) realloc(msg, msg_size);
160 						}
161 					}
162 				}
163 
164 				free(msg);
165 				break;
166 			}
167 
168 			case B_TUNE_REQUEST:
169 			case B_SYS_EX_END:
170 				SpraySystemCommon(data[0], 0, 0);
171 				break;
172 
173 			case B_MIDI_TIME_CODE:
174 			case B_SONG_SELECT:
175 			case B_CABLE_MESSAGE:
176 				read(fd, data + 1, 1);
177 				SpraySystemCommon(data[0], data[1], 0);
178 				break;
179 
180 			case B_SONG_POSITION:
181 				read(fd, data + 1, 2);
182 				SpraySystemCommon(data[0], data[1], data[2]);
183 				break;
184 
185 			case B_TIMING_CLOCK:
186 			case B_START:
187 			case B_CONTINUE:
188 			case B_STOP:
189 			case B_ACTIVE_SENSING:
190 			case B_SYSTEM_RESET:
191 				SpraySystemRealTime(data[0]);
192 				break;
193 		}
194 	}
195 
196 	return B_OK;
197 }
198 
199 //------------------------------------------------------------------------------
200