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