1 /*
2  *  Copyleft (C) 2000 David Griffiths <dave@pawfal.org>
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 
19 #include "Midi.h"
20 #include "NoteTable.h"
21 #include "unistd.h"
22 #include "sys/types.h"
23 #include "signal.h"
24 
25 #include "SpiralInfo.h"
26 
27 static const int MIDI_SCANBUFSIZE=256;
28 static const int MIDI_KEYOFFSET=0;
29 
MidiDevice()30 MidiDevice::MidiDevice()
31 {
32 	Init();
33 }
34 
~MidiDevice()35 MidiDevice::~MidiDevice()
36 {
37 	Close();
38 }
39 
40 
Close()41 void MidiDevice::Close()
42 {
43 	if (!SpiralInfo::WANTMIDI) return;
44 
45 	close(m_MidiFd);
46 	kill(m_ChildPID,9);
47 }
48 
49 
Init()50 void MidiDevice::Init()
51 {
52 	if (!SpiralInfo::WANTMIDI) return;
53 
54 	m_MidiFd = open(SpiralInfo::MIDIFILE.c_str(),O_RDONLY);
55 
56 	pipe(m_Pipefd);
57 	fcntl(m_Pipefd[0],F_SETFL,O_NONBLOCK);
58 
59 	m_ChildPID=fork();
60 
61 	if (!m_ChildPID)
62 	{
63 		CollectEvents();
64 	}
65 
66 }
67 
CollectEvents()68 void MidiDevice::CollectEvents()
69 {
70 	unsigned char buf[1];
71 	int count,n,nn;
72 	bool MessageSent;
73 	unsigned char data[3],last=0;
74 
75 	// constantly scan for relevent input,
76 	// and write it to the pipe
77 
78 	// filters out unhandled messages, and attempts to build
79 	// coherent messages to send to the midi handler
80 
81 	for(;;)
82 	{
83 		read(m_MidiFd,buf,1);
84 
85 		if (*buf!=248) // odd code that gets sent occasionally
86 		{
87 			if (*buf>=0x80) // we've got a opcode
88 			{
89 				last=data[0]=*buf;
90 
91 				// find out what the opcode means
92 				if(data[0]>=0x90 && data[0]<=0x9f) // note on event
93 				{
94 					// get the next two bytes
95 					read(m_MidiFd,&data[1],1);
96 					read(m_MidiFd,&data[2],1);
97 					write(m_Pipefd[1],data,3);
98 				}
99 				else if(data[0]>=0x80 && data[0]<=0x8f) // note off event
100 				{
101 					// get the next two bytes
102 					read(m_MidiFd,&data[1],1);
103 					read(m_MidiFd,&data[2],1);
104 					write(m_Pipefd[1],data,3);
105 				}
106 				else if(data[0]>=0xe0 && data[0]<=0xef) // pitch wheel event
107 				{
108 					// get the next two bytes
109 					read(m_MidiFd,&data[1],1);
110 					read(m_MidiFd,&data[2],1);
111 					write(m_Pipefd[1],data,3);
112 				}
113 				else if(data[0]>=0xb0 && data[0]<=0xbf) // parameter event
114 				{
115 					// get the next two byte
116 					read(m_MidiFd,&data[1],1);
117 					read(m_MidiFd,&data[2],1);
118 					write(m_Pipefd[1],data,3);
119 				}
120 				else
121 				{
122 					last=0; // we don't know this opcode
123 				}
124 			}
125 			else // more data
126 			{
127 				if (last!=0)
128 				{
129 					data[0]=last;
130 					data[1]=*buf;
131 
132 					// get the last byte if it's not a pressure message
133 					if(data[0]>=0xd0 && data[0]<=0xdf)
134 					{
135 						data[2]=0;
136 					}
137 					else
138 					{
139 						read(m_MidiFd,&data[2],1);
140 					}
141 
142 					write(m_Pipefd[1],data,3);
143 				}
144 			}
145 		}
146 	}
147 }
148 
GetEvent()149 MidiEvent MidiDevice::GetEvent()
150 {
151  	// This is a really quick hack based on the outputs from the
152 	// /dev/midi device. Doesn't really cope with anything difficult,
153 	// such as events being split by progam changes etc etc.
154 
155 	if (!SpiralInfo::WANTMIDI) return MidiEvent(MidiEvent::NONE,0,0,0);
156 
157 	unsigned char midi[3];
158 
159 	int count=read(m_Pipefd[0],midi,3);
160 
161 	// no message
162 	if (count<=0) return MidiEvent(MidiEvent::NONE,0,0,0);
163 
164 	MidiEvent::type MessageType=MidiEvent::NONE;
165 	int Volume=0,Octave=0,Note=0;
166 
167 	// todo: assumes midi channel 0 of 16
168 	switch (midi[0])
169 	{
170 		case 0x80: // note off
171 		{
172 			MessageType=MidiEvent::OFF;
173 			Octave=(midi[1]-MIDI_KEYOFFSET)/12;
174 
175 			// force range of our synth
176 			if (Octave<0) Octave=0;
177 			if (Octave>10) Octave=10;
178 
179 			Note=(midi[1]-MIDI_KEYOFFSET)%12;
180 
181 			break;
182 		}
183 		case 0x90: // note on
184 		{
185 			Volume = midi[2];
186 
187 			// cope with Roland equipment, where note on's
188 			// with zero velocity are sent as note offs.
189 
190 			if (Volume) MessageType=MidiEvent::ON;
191 			else MessageType=MidiEvent::OFF;
192 
193 			Octave=(midi[1]-MIDI_KEYOFFSET)/12;
194 
195 			// force range of our synth
196 			if (Octave<0) Octave=0;
197 			if (Octave>10) Octave=10;
198 
199 			Note=(midi[1]-MIDI_KEYOFFSET)%12;
200 			break;
201 		}
202 		case 0xb0: // parameter
203 		{
204 			MessageType=MidiEvent::PARAMETER;
205 			Octave=0;
206 			Note=midi[1];
207 			Volume=midi[2];
208 			break;
209 		}
210 		case 0xe0: // note pitchbend
211 		{
212 			MessageType=MidiEvent::PITCHBEND;
213 			// should probably take the first byte into account too.
214 			Volume=midi[2];
215 			break;
216 		}
217 	}
218 
219 	return MidiEvent(MessageType,Octave,Note,Volume);
220 }
221