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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 840 by persson, Sun Feb 26 13:00:08 2006 UTC revision 2500 by schoenebeck, Fri Jan 10 12:20:05 2014 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6   *   Copyright (C) 2005 Christian Schoenebeck                              *   *   Copyright (C) 2005 - 2014 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 23  Line 23 
23    
24  #include "MidiInputPort.h"  #include "MidiInputPort.h"
25    
26    #include "../../common/global_private.h"
27    #include "MidiInstrumentMapper.h"
28  #include "../../Sampler.h"  #include "../../Sampler.h"
29  #include "../../engines/EngineFactory.h"  #include "../../engines/EngineFactory.h"
30    #include "VirtualMidiDevice.h"
31    
32    #include <algorithm>
33    
34  namespace LinuxSampler {  namespace LinuxSampler {
35    
# Line 51  namespace LinuxSampler { Line 56  namespace LinuxSampler {
56          return std::vector<String>();          return std::vector<String>();
57      }      }
58    
59      void MidiInputPort::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {      void MidiInputPort::ParameterName::OnSetValue(String s) throw (Exception) {
60          return; /* FIXME: Nothing to do here */          return; /* FIXME: Nothing to do here */
61      }      }
62    
# Line 69  namespace LinuxSampler { Line 74  namespace LinuxSampler {
74          Parameters.clear();          Parameters.clear();
75      }      }
76    
77      MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber) {      MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
78            : MidiChannelMapReader(MidiChannelMap),
79              SysexListenersReader(SysexListeners),
80              virtualMidiDevicesReader(virtualMidiDevices),
81              noteOnVelocityFilterReader(noteOnVelocityFilter)
82        {
83          this->pDevice = pDevice;          this->pDevice = pDevice;
84          this->portNumber = portNumber;          this->portNumber = portNumber;
85            runningStatusBuf[0] = 0;
86          Parameters["NAME"] = new ParameterName(this);          Parameters["NAME"] = new ParameterName(this);
         pPreviousProgramChangeEngineChannel = NULL;  
87      }      }
88    
89      MidiInputDevice* MidiInputPort::GetDevice() {      MidiInputDevice* MidiInputPort::GetDevice() {
# Line 89  namespace LinuxSampler { Line 99  namespace LinuxSampler {
99      }      }
100    
101      void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {      void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
102          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
103            
104            // apply velocity filter (if any)
105            const std::vector<uint8_t>& velocityFilter = noteOnVelocityFilterReader.Lock();
106            if (!velocityFilter.empty()) Velocity = velocityFilter[Velocity];
107            noteOnVelocityFilterReader.Unlock();
108            
109            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
110          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
111          {          {
112              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
113              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
114              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel);
115          }          }
116          // dispatch event for engines listening to ALL MIDI channels          // dispatch event for engines listening to ALL MIDI channels
117          {          {
118              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
119              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
120              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel);
121          }          }
122          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
123    
124            // dispatch event to all low priority MIDI listeners
125            const std::vector<VirtualMidiDevice*>& listeners =
126                virtualMidiDevicesReader.Lock();
127            for (int i = 0; i < listeners.size(); ++i)
128                listeners[i]->SendNoteOnToDevice(Key, Velocity);
129            virtualMidiDevicesReader.Unlock();
130        }
131    
132        void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
133            if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
134            
135            // apply velocity filter (if any)
136            const std::vector<uint8_t>& velocityFilter = noteOnVelocityFilterReader.Lock();
137            if (!velocityFilter.empty()) Velocity = velocityFilter[Velocity];
138            noteOnVelocityFilterReader.Unlock();
139            
140            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
141            // dispatch event for engines listening to the same MIDI channel
142            {
143                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
144                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
145                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel, FragmentPos);
146            }
147            // dispatch event for engines listening to ALL MIDI channels
148            {
149                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
150                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
151                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, MidiChannel, FragmentPos);
152            }
153            MidiChannelMapReader.Unlock();
154    
155            // dispatch event to all low priority MIDI listeners
156            const std::vector<VirtualMidiDevice*>& listeners =
157                virtualMidiDevicesReader.Lock();
158            for (int i = 0; i < listeners.size(); ++i)
159                listeners[i]->SendNoteOnToDevice(Key, Velocity);
160            virtualMidiDevicesReader.Unlock();
161      }      }
162    
163      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
164          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
165            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
166          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
167          {          {
168              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
169              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
170              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel);
171          }          }
172          // dispatch event for engines listening to ALL MIDI channels          // dispatch event for engines listening to ALL MIDI channels
173          {          {
174              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
175              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
176              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel);
177          }          }
178          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
179    
180            // dispatch event to all low priority MIDI listeners
181            const std::vector<VirtualMidiDevice*>& listeners =
182                virtualMidiDevicesReader.Lock();
183            for (int i = 0; i < listeners.size(); ++i)
184                listeners[i]->SendNoteOffToDevice(Key, Velocity);
185            virtualMidiDevicesReader.Unlock();
186        }
187    
188        void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
189            if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;
190            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
191            // dispatch event for engines listening to the same MIDI channel
192            {
193                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
194                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
195                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel, FragmentPos);
196            }
197            // dispatch event for engines listening to ALL MIDI channels
198            {
199                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
200                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
201                for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, MidiChannel, FragmentPos);
202            }
203            MidiChannelMapReader.Unlock();
204    
205            // dispatch event to all low priority MIDI listeners
206            const std::vector<VirtualMidiDevice*>& listeners =
207                virtualMidiDevicesReader.Lock();
208            for (int i = 0; i < listeners.size(); ++i)
209                listeners[i]->SendNoteOffToDevice(Key, Velocity);
210            virtualMidiDevicesReader.Unlock();
211      }      }
212    
213      void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {      void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
214          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
215            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
216            // dispatch event for engines listening to the same MIDI channel
217            {
218                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
219                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
220                for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel);
221            }
222            // dispatch event for engines listening to ALL MIDI channels
223            {
224                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
225                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
226                for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel);
227            }
228            MidiChannelMapReader.Unlock();
229        }
230    
231        void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel, int32_t FragmentPos) {
232            if (Pitch < -8192 || Pitch > 8191 || MidiChannel > 16) return;
233            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
234          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
235          {          {
236              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
237              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
238              for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);              for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel, FragmentPos);
239          }          }
240          // dispatch event for engines listening to ALL MIDI channels          // dispatch event for engines listening to ALL MIDI channels
241          {          {
242              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
243              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
244              for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);              for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch, MidiChannel, FragmentPos);
245          }          }
246          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
247      }      }
248    
249      void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {      void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
250          const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();          if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
251            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
252          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
253          {          {
254              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
255              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
256              for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);              for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel);
257          }          }
258          // dispatch event for engines listening to ALL MIDI channels          // dispatch event for engines listening to ALL MIDI channels
259          {          {
260              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();              std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
261              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();              std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
262              for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);              for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel);
263          }          }
264          MidiChannelMap.Unlock();          MidiChannelMapReader.Unlock();
265            
266            // dispatch event to all low priority MIDI listeners
267            const std::vector<VirtualMidiDevice*>& listeners =
268                virtualMidiDevicesReader.Lock();
269            for (int i = 0; i < listeners.size(); ++i)
270                listeners[i]->SendCCToDevice(Controller, Value);
271            virtualMidiDevicesReader.Unlock();
272        }
273    
274        void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel, int32_t FragmentPos) {
275            if (Controller > 128 || Value > 127 || MidiChannel > 16) return;
276            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
277            // dispatch event for engines listening to the same MIDI channel
278            {
279                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
280                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
281                for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel, FragmentPos);
282            }
283            // dispatch event for engines listening to ALL MIDI channels
284            {
285                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
286                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
287                for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value, MidiChannel, FragmentPos);
288            }
289            MidiChannelMapReader.Unlock();
290            
291            // dispatch event to all low priority MIDI listeners
292            const std::vector<VirtualMidiDevice*>& listeners =
293                virtualMidiDevicesReader.Lock();
294            for (int i = 0; i < listeners.size(); ++i)
295                listeners[i]->SendCCToDevice(Controller, Value);
296            virtualMidiDevicesReader.Unlock();
297      }      }
298    
299      void MidiInputPort::DispatchSysex(void* pData, uint Size) {      void MidiInputPort::DispatchSysex(void* pData, uint Size) {
300            const std::set<Engine*> allEngines = SysexListenersReader.Lock();
301          // dispatch event to all engine instances          // dispatch event to all engine instances
302          std::set<Engine*>::iterator engineiter = EngineFactory::EngineInstances().begin();          std::set<Engine*>::iterator engineiter = allEngines.begin();
303          std::set<Engine*>::iterator end        = EngineFactory::EngineInstances().end();          std::set<Engine*>::iterator end        = allEngines.end();
304          for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size);          for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size, this);
305            SysexListenersReader.Unlock();
306      }      }
307    
308      void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {      void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
309            if (Program > 127 || MidiChannel > 16) return;
310          if (!pDevice || !pDevice->pSampler) {          if (!pDevice || !pDevice->pSampler) {
311              std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."              std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
312                        << "This is a bug, please report it!\n" << std::flush;                        << "This is a bug, please report it!\n" << std::flush;
313              return;              return;
314          }          }
315    
316          Sampler*        pSampler        = (Sampler*) pDevice->pSampler;          const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
317          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(Program);          // dispatch event for engines listening to the same MIDI channel
318          if (!pSamplerChannel) return;          {
319                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
320                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
321                for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
322            }
323            // dispatch event for engines listening to ALL MIDI channels
324            {
325                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
326                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
327                for (; engineiter != end; engineiter++) (*engineiter)->SendProgramChange(Program);
328            }
329            MidiChannelMapReader.Unlock();
330        }
331    
332          EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();      void MidiInputPort::DispatchBankSelectMsb(uint8_t BankMSB, uint MidiChannel) {
333          if (!pEngineChannel) return;          if (BankMSB > 127 || MidiChannel > 16) return;
334            if (!pDevice || !pDevice->pSampler) {
335                std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select MSB."
336                          << "This is a bug, please report it!\n" << std::flush;
337                return;
338            }
339            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
340            // dispatch event for engines listening to the same MIDI channel
341            {
342                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
343                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
344                // according to the MIDI specs, a bank select should not alter the patch
345                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
346            }
347            // dispatch event for engines listening to ALL MIDI channels
348            {
349                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
350                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
351                // according to the MIDI specs, a bank select should not alter the patch
352                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
353            }
354            MidiChannelMapReader.Unlock();
355        }
356    
357          // disconnect from the engine channel which was connected by the last PC event      void MidiInputPort::DispatchBankSelectLsb(uint8_t BankLSB, uint MidiChannel) {
358          if (pPreviousProgramChangeEngineChannel)          if (BankLSB > 127 || MidiChannel > 16) return;
359              Disconnect(pPreviousProgramChangeEngineChannel);          if (!pDevice || !pDevice->pSampler) {
360                std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select LSB."
361                          << "This is a bug, please report it!\n" << std::flush;
362                return;
363            }
364            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
365            // dispatch event for engines listening to the same MIDI channel
366            {
367                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
368                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
369                // according to the MIDI specs, a bank select should not alter the patch
370                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
371            }
372            // dispatch event for engines listening to ALL MIDI channels
373            {
374                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
375                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
376                // according to the MIDI specs, a bank select should not alter the patch
377                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
378            }
379            MidiChannelMapReader.Unlock();
380        }
381        
382        /**
383         * Handles the so called MIDI "running status" mode, which allows devices
384         * to reduce bandwidth (data reduction).
385         *
386         * If the passed in MIDI data is regular MIDI data, this method will simply
387         * return the original data pointer and just stores the status byte for
388         * potential "running status" event eventually coming next.
389         *
390         * If the passed in MIDI data however seems to be in "running status" mode,
391         * this method will return another buffer, which allows the MIDI parser
392         * to handle the MIDI data as usually with "normal" MIDI data.
393         */
394        uint8_t* MidiInputPort::handleRunningStatus(uint8_t* pData) {
395            if ((pData[0] & 0x80) || !runningStatusBuf[0]) {
396                // store status byte for eventual "running status" in next event
397                if (pData[0] & 0x80) {
398                    if (pData[0] < 0xf0) {
399                        // "running status" is only allowed for channel messages
400                        runningStatusBuf[0] = pData[0];
401                    } else if (pData[0] < 0xf8) {
402                        // "system common" messages (0xf0..0xf7) shall reset any running
403                        // status, however "realtime" messages (0xf8..0xff) shall be
404                        // ignored here
405                        runningStatusBuf[0] = 0;
406                    }
407                }
408                // it's either a regular status byte, or some invalid "running status"
409                return pData;
410            } else { // "running status" mode ...
411                const uint8_t type = runningStatusBuf[0] & 0xf0;
412                const int size = (type == 0xc0 || type == 0xd0) ? 1 : 2; // only program change & channel pressure have 1 data bytes
413                memcpy(&runningStatusBuf[1], pData, size);
414                return runningStatusBuf;
415            }
416        }
417    
418          // now connect to the new engine channel and remember it      void MidiInputPort::DispatchRaw(uint8_t* pData) {
419          try {          pData = handleRunningStatus(pData);
420              Connect(pEngineChannel, (midi_chan_t) MidiChannel);          
421              pPreviousProgramChangeEngineChannel = pEngineChannel;          uint8_t channel = pData[0] & 0x0f;
422            switch (pData[0] & 0xf0) {
423            case 0x80:
424                DispatchNoteOff(pData[1], pData[2], channel);
425                break;
426            case 0x90:
427                if (pData[2]) {
428                    DispatchNoteOn(pData[1], pData[2], channel);
429                } else {
430                    DispatchNoteOff(pData[1], pData[2], channel);
431                }
432                break;
433            case 0xb0:
434                if (pData[1] == 0) {
435                    DispatchBankSelectMsb(pData[2], channel);
436                } else if (pData[1] == 32) {
437                    DispatchBankSelectLsb(pData[2], channel);
438                }
439                DispatchControlChange(pData[1], pData[2], channel);
440                break;
441            case 0xc0:
442                DispatchProgramChange(pData[1], channel);
443                break;
444            case 0xd0:
445                DispatchControlChange(128, pData[1], channel);
446                break;
447            case 0xe0:
448                DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel);
449                break;
450            }
451        }
452    
453        void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) {
454            pData = handleRunningStatus(pData);
455            
456            uint8_t channel = pData[0] & 0x0f;
457            switch (pData[0] & 0xf0) {
458            case 0x80:
459                DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
460                break;
461            case 0x90:
462                if (pData[2]) {
463                    DispatchNoteOn(pData[1], pData[2], channel, FragmentPos);
464                } else {
465                    DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
466                }
467                break;
468            case 0xb0:
469                if (pData[1] == 0) {
470                    DispatchBankSelectMsb(pData[2], channel);
471                } else if (pData[1] == 32) {
472                    DispatchBankSelectLsb(pData[2], channel);
473                }
474                DispatchControlChange(pData[1], pData[2], channel, FragmentPos);
475                break;
476            case 0xc0:
477                DispatchProgramChange(pData[1], channel);
478                break;
479            case 0xd0:
480                DispatchControlChange(128, pData[1], channel, FragmentPos);
481                break;
482            case 0xe0:
483                DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel, FragmentPos);
484                break;
485            }
486        }
487        
488        void MidiInputPort::SetNoteOnVelocityFilter(const std::vector<uint8_t>& filter) {
489            if (filter.size() != 128 && filter.size() != 0)
490                throw MidiInputException("Note on velocity filter must be either of size 128 or 0");
491            
492            // check the value range of the filter
493            if (!filter.empty())
494                for (int i = 0; i < 128; i++)
495                    if (filter[i] > 127)
496                        throw MidiInputException("Invalid note on velocity filter, values must be in range 0 .. 127");
497            
498            // apply new filter ...
499            LockGuard lock(noteOnVelocityFilterMutex);
500            // double buffer ... double work ...
501            {
502                std::vector<uint8_t>& config =
503                    noteOnVelocityFilter.GetConfigForUpdate();
504                config = filter;
505            }
506            {
507                std::vector<uint8_t>& config =
508                    noteOnVelocityFilter.SwitchConfig();
509                config = filter;
510          }          }
         catch (...) { /* NOOP */ }  
511      }      }
512    
513      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
# Line 194  namespace LinuxSampler { Line 515  namespace LinuxSampler {
515              throw MidiInputException("MIDI channel index out of bounds");              throw MidiInputException("MIDI channel index out of bounds");
516    
517          // first check if desired connection is already established          // first check if desired connection is already established
518          MidiChannelMapMutex.Lock();          {
519          MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();              LockGuard lock(MidiChannelMapMutex);
520          bool bAlreadyDone = midiChannelMap[MidiChannel].count(pEngineChannel);              MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
521          MidiChannelMapMutex.Unlock();              if (midiChannelMap[MidiChannel].count(pEngineChannel)) return;
522          if (bAlreadyDone) return;          }
523    
524          // remove all other connections of that engine channel (if any)          // remove all other connections of that engine channel (if any)
525          Disconnect(pEngineChannel);          Disconnect(pEngineChannel);
526    
527          // register engine channel on the desired MIDI channel          // register engine channel on the desired MIDI channel
528          MidiChannelMapMutex.Lock();          {
529          MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);              LockGuard lock(MidiChannelMapMutex);
530          MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);              MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
531          MidiChannelMapMutex.Unlock();              MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
532            }
533    
534          // inform engine channel about this connection          // inform engine channel about this connection
535          pEngineChannel->Connect(this, MidiChannel);          pEngineChannel->Connect(this);
536            if (pEngineChannel->MidiChannel() != MidiChannel)
537                pEngineChannel->SetMidiChannel(MidiChannel);
538    
539          // mark engine channel as changed          // mark engine channel as changed
540          pEngineChannel->StatusChanged(true);          pEngineChannel->StatusChanged(true);
# Line 222  namespace LinuxSampler { Line 546  namespace LinuxSampler {
546          bool bChannelFound = false;          bool bChannelFound = false;
547    
548          // unregister engine channel from all MIDI channels          // unregister engine channel from all MIDI channels
         MidiChannelMapMutex.Lock();  
549          try {          try {
550                LockGuard lock(MidiChannelMapMutex);
551              {              {
552                  MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();                  MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
553                  for (int i = 0; i <= 16; i++) {                  for (int i = 0; i <= 16; i++) {
# Line 241  namespace LinuxSampler { Line 565  namespace LinuxSampler {
565              }              }
566          }          }
567          catch(...) { /* NOOP */ }          catch(...) { /* NOOP */ }
         MidiChannelMapMutex.Unlock();  
568    
569          // inform engine channel about the disconnection (if there is one)          // inform engine channel about the disconnection (if there is one)
570          if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();          if (bChannelFound) pEngineChannel->Disconnect(this);
571    
572          // mark engine channel as changed          // mark engine channel as changed
573          pEngineChannel->StatusChanged(true);          pEngineChannel->StatusChanged(true);
574      }      }
575    
576        SynchronizedConfig<std::set<LinuxSampler::Engine*> > MidiInputPort::SysexListeners;
577    
578        void MidiInputPort::AddSysexListener(Engine* engine) {
579            std::pair<std::set<Engine*>::iterator, bool> p = SysexListeners.GetConfigForUpdate().insert(engine);
580            if (p.second) SysexListeners.SwitchConfig().insert(engine);
581        }
582    
583        bool MidiInputPort::RemoveSysexListener(Engine* engine) {
584            int count = SysexListeners.GetConfigForUpdate().erase(engine);
585            if (count) SysexListeners.SwitchConfig().erase(engine);
586            return count;
587        }
588    
589        void MidiInputPort::Connect(VirtualMidiDevice* pDevice) {
590            LockGuard lock(virtualMidiDevicesMutex);
591            // double buffer ... double work ...
592            {
593                std::vector<VirtualMidiDevice*>& devices =
594                    virtualMidiDevices.GetConfigForUpdate();
595                devices.push_back(pDevice);
596            }
597            {
598                std::vector<VirtualMidiDevice*>& devices =
599                    virtualMidiDevices.SwitchConfig();
600                devices.push_back(pDevice);
601            }
602        }
603    
604        void MidiInputPort::Disconnect(VirtualMidiDevice* pDevice) {
605            LockGuard lock(virtualMidiDevicesMutex);
606            // double buffer ... double work ...
607            {
608                std::vector<VirtualMidiDevice*>& devices =
609                    virtualMidiDevices.GetConfigForUpdate();
610                devices.erase(std::find(devices.begin(), devices.end(), pDevice));
611            }
612            {
613                std::vector<VirtualMidiDevice*>& devices =
614                    virtualMidiDevices.SwitchConfig();
615                devices.erase(std::find(devices.begin(), devices.end(), pDevice));
616            }
617        }
618    
619        int MidiInputPort::expectedEventSize(unsigned char byte) {
620            if (!(byte & 0x80) && runningStatusBuf[0])
621                byte = runningStatusBuf[0]; // "running status" mode
622            
623            if (byte < 0x80) return -1; // not a valid status byte
624            if (byte < 0xC0) return 3; // note on/off, note pressure, control change
625            if (byte < 0xE0) return 2; // program change, channel pressure
626            if (byte < 0xF0) return 3; // pitch wheel
627            if (byte == 0xF0) return -1; // sysex message (variable size)
628            if (byte == 0xF1) return 2; // time code per quarter frame
629            if (byte == 0xF2) return 3; // sys. common song position pointer
630            if (byte == 0xF3) return 2; // sys. common song select
631            if (byte == 0xF4) return -1; // sys. common undefined / reserved
632            if (byte == 0xF5) return -1; // sys. common undefined / reserved
633            return 1; // tune request, end of SysEx, system real-time events
634        }
635    
636  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.840  
changed lines
  Added in v.2500

  ViewVC Help
Powered by ViewVC