/[svn]/linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/drivers/midi/MidiInputPort.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 906 - (hide annotations) (download)
Sun Jul 23 16:44:08 2006 UTC (17 years, 9 months ago) by schoenebeck
File size: 16165 byte(s)
* MIDI driver API extension for MIDI drivers which already supply exact
  time stamps for events (i.e. for offline rendering based MIDI drivers)

1 schoenebeck 221 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 880 * Copyright (C) 2005, 2006 Christian Schoenebeck *
7 schoenebeck 221 * *
8     * This program is free software; you can redistribute it and/or modify *
9     * it under the terms of the GNU General Public License as published by *
10     * the Free Software Foundation; either version 2 of the License, or *
11     * (at your option) any later version. *
12     * *
13     * This program is distributed in the hope that it will be useful, *
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16     * GNU General Public License for more details. *
17     * *
18     * You should have received a copy of the GNU General Public License *
19     * along with this program; if not, write to the Free Software *
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21     * MA 02111-1307 USA *
22     ***************************************************************************/
23    
24     #include "MidiInputPort.h"
25    
26 schoenebeck 551 #include "../../Sampler.h"
27 schoenebeck 775 #include "../../engines/EngineFactory.h"
28 schoenebeck 551
29 schoenebeck 221 namespace LinuxSampler {
30    
31     // *************** ParameterName ***************
32     // *
33    
34     MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort) : DeviceRuntimeParameterString("Port " + ToString(pPort->GetPortNumber())) {
35     this->pPort = pPort;
36     }
37    
38     MidiInputPort::ParameterName::ParameterName(MidiInputPort* pPort, String val) : DeviceRuntimeParameterString(val) {
39     this->pPort = pPort;
40     }
41    
42     String MidiInputPort::ParameterName::Description() {
43     return "Name for this port";
44     }
45    
46     bool MidiInputPort::ParameterName::Fix() {
47     return false;
48     }
49    
50     std::vector<String> MidiInputPort::ParameterName::PossibilitiesAsString() {
51     return std::vector<String>();
52     }
53    
54 schoenebeck 880 void MidiInputPort::ParameterName::OnSetValue(String s) throw (Exception) {
55 schoenebeck 221 return; /* FIXME: Nothing to do here */
56     }
57    
58    
59    
60     // *************** MidiInputPort ***************
61     // *
62    
63     MidiInputPort::~MidiInputPort() {
64     std::map<String,DeviceRuntimeParameter*>::iterator iter = Parameters.begin();
65     while (iter != Parameters.end()) {
66     delete iter->second;
67     iter++;
68     }
69 persson 836 Parameters.clear();
70 schoenebeck 221 }
71    
72 persson 846 MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
73     : MidiChannelMapReader(MidiChannelMap),
74     SysexListenersReader(SysexListeners) {
75 schoenebeck 221 this->pDevice = pDevice;
76     this->portNumber = portNumber;
77     Parameters["NAME"] = new ParameterName(this);
78 schoenebeck 551 pPreviousProgramChangeEngineChannel = NULL;
79 schoenebeck 221 }
80    
81     MidiInputDevice* MidiInputPort::GetDevice() {
82     return pDevice;
83     }
84    
85     uint MidiInputPort::GetPortNumber() {
86     return portNumber;
87     }
88    
89     std::map<String,DeviceRuntimeParameter*> MidiInputPort::PortParameters() {
90     return Parameters;
91     }
92    
93     void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
94 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
95 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
96     {
97 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
98     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
99 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
100     }
101     // dispatch event for engines listening to ALL MIDI channels
102     {
103 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
104     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
105 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
106     }
107 persson 846 MidiChannelMapReader.Unlock();
108 schoenebeck 221 }
109    
110 schoenebeck 906 void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
111     const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
112     // dispatch event for engines listening to the same MIDI channel
113     {
114     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
115     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
116     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
117     }
118     // dispatch event for engines listening to ALL MIDI channels
119     {
120     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
121     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
122     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
123     }
124     MidiChannelMapReader.Unlock();
125     }
126    
127 schoenebeck 221 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
128 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
129 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
130     {
131 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
132     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
133 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
134     }
135     // dispatch event for engines listening to ALL MIDI channels
136     {
137 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
138     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
139 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
140     }
141 persson 846 MidiChannelMapReader.Unlock();
142 schoenebeck 221 }
143    
144 schoenebeck 906 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
145     const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
146     // dispatch event for engines listening to the same MIDI channel
147     {
148     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
149     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
150     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
151     }
152     // dispatch event for engines listening to ALL MIDI channels
153     {
154     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
155     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
156     for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
157     }
158     MidiChannelMapReader.Unlock();
159     }
160    
161 schoenebeck 221 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
162 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
163 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
164     {
165 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
166     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
167 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
168     }
169     // dispatch event for engines listening to ALL MIDI channels
170     {
171 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
172     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
173 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
174     }
175 persson 846 MidiChannelMapReader.Unlock();
176 schoenebeck 221 }
177    
178 schoenebeck 906 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos) {
179     const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
180     // dispatch event for engines listening to the same MIDI channel
181     {
182     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
183     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
184     for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
185     }
186     // dispatch event for engines listening to ALL MIDI channels
187     {
188     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
189     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
190     for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, FragmentPos);
191     }
192     MidiChannelMapReader.Unlock();
193     }
194    
195 schoenebeck 221 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
196 persson 846 const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
197 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
198     {
199 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
200     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
201 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
202     }
203     // dispatch event for engines listening to ALL MIDI channels
204     {
205 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
206     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
207 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
208     }
209 persson 846 MidiChannelMapReader.Unlock();
210 schoenebeck 221 }
211    
212 schoenebeck 906 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos) {
213     const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
214     // dispatch event for engines listening to the same MIDI channel
215     {
216     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
217     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
218     for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
219     }
220     // dispatch event for engines listening to ALL MIDI channels
221     {
222     std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
223     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
224     for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, FragmentPos);
225     }
226     MidiChannelMapReader.Unlock();
227     }
228    
229 schoenebeck 244 void MidiInputPort::DispatchSysex(void* pData, uint Size) {
230 persson 846 const std::set<Engine*> allEngines = SysexListenersReader.Lock();
231 schoenebeck 775 // dispatch event to all engine instances
232 persson 846 std::set<Engine*>::iterator engineiter = allEngines.begin();
233     std::set<Engine*>::iterator end = allEngines.end();
234 schoenebeck 775 for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size);
235 persson 846 SysexListenersReader.Unlock();
236 schoenebeck 244 }
237    
238 schoenebeck 670 void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
239 schoenebeck 551 if (!pDevice || !pDevice->pSampler) {
240     std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
241     << "This is a bug, please report it!\n" << std::flush;
242     return;
243     }
244    
245     Sampler* pSampler = (Sampler*) pDevice->pSampler;
246     SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(Program);
247     if (!pSamplerChannel) return;
248    
249     EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
250     if (!pEngineChannel) return;
251    
252     // disconnect from the engine channel which was connected by the last PC event
253     if (pPreviousProgramChangeEngineChannel)
254     Disconnect(pPreviousProgramChangeEngineChannel);
255 schoenebeck 670
256 schoenebeck 551 // now connect to the new engine channel and remember it
257     try {
258     Connect(pEngineChannel, (midi_chan_t) MidiChannel);
259     pPreviousProgramChangeEngineChannel = pEngineChannel;
260     }
261     catch (...) { /* NOOP */ }
262     }
263    
264 schoenebeck 411 void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
265 schoenebeck 221 if (MidiChannel < 0 || MidiChannel > 16)
266     throw MidiInputException("MIDI channel index out of bounds");
267 schoenebeck 670
268 persson 840 // first check if desired connection is already established
269 schoenebeck 675 MidiChannelMapMutex.Lock();
270 persson 840 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
271     bool bAlreadyDone = midiChannelMap[MidiChannel].count(pEngineChannel);
272 schoenebeck 675 MidiChannelMapMutex.Unlock();
273     if (bAlreadyDone) return;
274    
275     // remove all other connections of that engine channel (if any)
276 schoenebeck 411 Disconnect(pEngineChannel);
277 schoenebeck 670
278 schoenebeck 675 // register engine channel on the desired MIDI channel
279 schoenebeck 551 MidiChannelMapMutex.Lock();
280 persson 840 MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
281     MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
282 schoenebeck 551 MidiChannelMapMutex.Unlock();
283 schoenebeck 670
284 schoenebeck 675 // inform engine channel about this connection
285     pEngineChannel->Connect(this, MidiChannel);
286    
287 schoenebeck 670 // mark engine channel as changed
288     pEngineChannel->StatusChanged(true);
289 schoenebeck 221 }
290    
291 schoenebeck 411 void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) {
292 schoenebeck 675 if (!pEngineChannel) return;
293    
294     bool bChannelFound = false;
295    
296     // unregister engine channel from all MIDI channels
297 schoenebeck 551 MidiChannelMapMutex.Lock();
298 schoenebeck 675 try {
299 persson 840 {
300     MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
301     for (int i = 0; i <= 16; i++) {
302     bChannelFound |= midiChannelMap[i].count(pEngineChannel);
303     midiChannelMap[i].erase(pEngineChannel);
304     }
305 schoenebeck 675 }
306 persson 840 // do the same update again, after switching to the other config
307     {
308     MidiChannelMap_t& midiChannelMap = MidiChannelMap.SwitchConfig();
309     for (int i = 0; i <= 16; i++) {
310     bChannelFound |= midiChannelMap[i].count(pEngineChannel);
311     midiChannelMap[i].erase(pEngineChannel);
312     }
313     }
314 schoenebeck 675 }
315 schoenebeck 221 catch(...) { /* NOOP */ }
316 schoenebeck 551 MidiChannelMapMutex.Unlock();
317 schoenebeck 675
318     // inform engine channel about the disconnection (if there is one)
319     if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();
320    
321 schoenebeck 670 // mark engine channel as changed
322     pEngineChannel->StatusChanged(true);
323 schoenebeck 221 }
324    
325 persson 846 SynchronizedConfig<std::set<LinuxSampler::Engine*> > MidiInputPort::SysexListeners;
326    
327     void MidiInputPort::AddSysexListener(Engine* engine) {
328     std::pair<std::set<Engine*>::iterator, bool> p = SysexListeners.GetConfigForUpdate().insert(engine);
329     if (p.second) SysexListeners.SwitchConfig().insert(engine);
330     }
331    
332     bool MidiInputPort::RemoveSysexListener(Engine* engine) {
333     int count = SysexListeners.GetConfigForUpdate().erase(engine);
334     if (count) SysexListeners.SwitchConfig().erase(engine);
335     return count;
336     }
337    
338 schoenebeck 221 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC