/[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 922 by persson, Mon Oct 2 18:40:10 2006 UTC revision 1887 by persson, Sat Apr 18 08:17:16 2009 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, 2006 Christian Schoenebeck                        *   *   Copyright (C) 2005 - 2009 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 71  namespace LinuxSampler { Line 76  namespace LinuxSampler {
76    
77      MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)      MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber)
78          : MidiChannelMapReader(MidiChannelMap),          : MidiChannelMapReader(MidiChannelMap),
79            SysexListenersReader(SysexListeners) {            SysexListenersReader(SysexListeners),
80              virtualMidiDevicesReader(virtualMidiDevices) {
81          this->pDevice = pDevice;          this->pDevice = pDevice;
82          this->portNumber = portNumber;          this->portNumber = portNumber;
83          Parameters["NAME"] = new ParameterName(this);          Parameters["NAME"] = new ParameterName(this);
         pPreviousProgramChangeEngineChannel = NULL;  
84      }      }
85    
86      MidiInputDevice* MidiInputPort::GetDevice() {      MidiInputDevice* MidiInputPort::GetDevice() {
# Line 106  namespace LinuxSampler { Line 111  namespace LinuxSampler {
111              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
112          }          }
113          MidiChannelMapReader.Unlock();          MidiChannelMapReader.Unlock();
114    
115            // dispatch event to all low priority MIDI listeners
116            const std::vector<VirtualMidiDevice*>& listeners =
117                virtualMidiDevicesReader.Lock();
118            for (int i = 0; i < listeners.size(); ++i)
119                listeners[i]->SendNoteOnToDevice(Key, Velocity);
120            virtualMidiDevicesReader.Unlock();
121      }      }
122    
123      void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {      void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
# Line 124  namespace LinuxSampler { Line 136  namespace LinuxSampler {
136              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity, FragmentPos);
137          }          }
138          MidiChannelMapReader.Unlock();          MidiChannelMapReader.Unlock();
139    
140            // dispatch event to all low priority MIDI listeners
141            const std::vector<VirtualMidiDevice*>& listeners =
142                virtualMidiDevicesReader.Lock();
143            for (int i = 0; i < listeners.size(); ++i)
144                listeners[i]->SendNoteOnToDevice(Key, Velocity);
145            virtualMidiDevicesReader.Unlock();
146      }      }
147    
148      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
# Line 142  namespace LinuxSampler { Line 161  namespace LinuxSampler {
161              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
162          }          }
163          MidiChannelMapReader.Unlock();          MidiChannelMapReader.Unlock();
164    
165            // dispatch event to all low priority MIDI listeners
166            const std::vector<VirtualMidiDevice*>& listeners =
167                virtualMidiDevicesReader.Lock();
168            for (int i = 0; i < listeners.size(); ++i)
169                listeners[i]->SendNoteOffToDevice(Key, Velocity);
170            virtualMidiDevicesReader.Unlock();
171      }      }
172    
173      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {      void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel, int32_t FragmentPos) {
# Line 160  namespace LinuxSampler { Line 186  namespace LinuxSampler {
186              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);              for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity, FragmentPos);
187          }          }
188          MidiChannelMapReader.Unlock();          MidiChannelMapReader.Unlock();
189    
190            // dispatch event to all low priority MIDI listeners
191            const std::vector<VirtualMidiDevice*>& listeners =
192                virtualMidiDevicesReader.Lock();
193            for (int i = 0; i < listeners.size(); ++i)
194                listeners[i]->SendNoteOffToDevice(Key, Velocity);
195            virtualMidiDevicesReader.Unlock();
196      }      }
197    
198      void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {      void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
# Line 239  namespace LinuxSampler { Line 272  namespace LinuxSampler {
272          // dispatch event to all engine instances          // dispatch event to all engine instances
273          std::set<Engine*>::iterator engineiter = allEngines.begin();          std::set<Engine*>::iterator engineiter = allEngines.begin();
274          std::set<Engine*>::iterator end        = allEngines.end();          std::set<Engine*>::iterator end        = allEngines.end();
275          for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size);          for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size, this);
276          SysexListenersReader.Unlock();          SysexListenersReader.Unlock();
277      }      }
278    
279      void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {      void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
280            dmsg(1,("Received MIDI program change (prog=%d,ch=%d)\n",Program,MidiChannel));
281          if (Program > 127 || MidiChannel > 16) return;          if (Program > 127 || MidiChannel > 16) return;
282          if (!pDevice || !pDevice->pSampler) {          if (!pDevice || !pDevice->pSampler) {
283              std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."              std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
284                        << "This is a bug, please report it!\n" << std::flush;                        << "This is a bug, please report it!\n" << std::flush;
285              return;              return;
286          }          }
287            std::vector<int> maps = MidiInstrumentMapper::Maps();
288            if (maps.empty()) return;
289    
290          Sampler*        pSampler        = (Sampler*) pDevice->pSampler;          const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
291          SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(Program);          // dispatch event for engines listening to the same MIDI channel
292          if (!pSamplerChannel) return;          {
293                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
294                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
295                for (; engineiter != end; engineiter++) {
296                    (*engineiter)->SetMidiProgram(Program);
297                    if ((*engineiter)->UsesNoMidiInstrumentMap()) continue;
298                    if (MidiInstrumentMapper::GetMapCount() == 0) continue;
299                    // retrieve the MIDI instrument map this engine channel is assigned to
300                    int iMapID = ((*engineiter)->UsesDefaultMidiInstrumentMap())
301                        ? MidiInstrumentMapper::GetDefaultMap() /*default*/ : (*engineiter)->GetMidiInstrumentMap();
302                    // is there an entry for this MIDI bank&prog pair in that map?
303                    midi_prog_index_t midiIndex;
304                    midiIndex.midi_bank_msb = (*engineiter)->GetMidiBankMsb();
305                    midiIndex.midi_bank_lsb = (*engineiter)->GetMidiBankLsb();
306                    midiIndex.midi_prog     = (*engineiter)->GetMidiProgram();
307                    optional<MidiInstrumentMapper::entry_t> mapping =
308                        MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
309                    if (mapping) { // if mapping exists ...
310                        InstrumentManager::instrument_id_t id;
311                        id.FileName = mapping->InstrumentFile;
312                        id.Index    = mapping->InstrumentIndex;
313                        //TODO: we should switch the engine type here
314                        InstrumentManager::LoadInstrumentInBackground(id, *engineiter);
315                        (*engineiter)->Volume(mapping->Volume);
316                    }
317                }
318            }
319            // dispatch event for engines listening to ALL MIDI channels
320            {
321                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
322                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
323                for (; engineiter != end; engineiter++) {
324                    (*engineiter)->SetMidiProgram(Program);
325                    if ((*engineiter)->UsesNoMidiInstrumentMap()) continue;
326                    if (MidiInstrumentMapper::GetMapCount() == 0) continue;
327                    // retrieve the MIDI instrument map this engine channel is assigned to
328                    int iMapID = ((*engineiter)->UsesDefaultMidiInstrumentMap())
329                        ? MidiInstrumentMapper::GetDefaultMap() /*default*/ : (*engineiter)->GetMidiInstrumentMap();
330                    // is there an entry for this MIDI bank&prog pair in that map?
331                    midi_prog_index_t midiIndex;
332                    midiIndex.midi_bank_msb = (*engineiter)->GetMidiBankMsb();
333                    midiIndex.midi_bank_lsb = (*engineiter)->GetMidiBankLsb();
334                    midiIndex.midi_prog     = (*engineiter)->GetMidiProgram();
335                    optional<MidiInstrumentMapper::entry_t> mapping =
336                        MidiInstrumentMapper::GetEntry(iMapID, midiIndex);
337                    if (mapping) { // if mapping exists ...
338                        InstrumentManager::instrument_id_t id;
339                        id.FileName = mapping->InstrumentFile;
340                        id.Index    = mapping->InstrumentIndex;
341                        //TODO: we should switch the engine type here
342                        InstrumentManager::LoadInstrumentInBackground(id, *engineiter);
343                        (*engineiter)->Volume(mapping->Volume);
344                    }
345                }
346            }
347            MidiChannelMapReader.Unlock();
348        }
349    
350          EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();      void MidiInputPort::DispatchBankSelectMsb(uint8_t BankMSB, uint MidiChannel) {
351          if (!pEngineChannel) return;          if (BankMSB > 127 || MidiChannel > 16) return;
352            if (!pDevice || !pDevice->pSampler) {
353                std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select MSB."
354                          << "This is a bug, please report it!\n" << std::flush;
355                return;
356            }
357            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
358            // dispatch event for engines listening to the same MIDI channel
359            {
360                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
361                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
362                // according to the MIDI specs, a bank select should not alter the patch
363                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
364            }
365            // dispatch event for engines listening to ALL MIDI channels
366            {
367                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
368                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
369                // according to the MIDI specs, a bank select should not alter the patch
370                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankMsb(BankMSB);
371            }
372            MidiChannelMapReader.Unlock();
373        }
374    
375          // disconnect from the engine channel which was connected by the last PC event      void MidiInputPort::DispatchBankSelectLsb(uint8_t BankLSB, uint MidiChannel) {
376          if (pPreviousProgramChangeEngineChannel)          if (BankLSB > 127 || MidiChannel > 16) return;
377              Disconnect(pPreviousProgramChangeEngineChannel);          if (!pDevice || !pDevice->pSampler) {
378                std::cerr << "MidiInputPort: ERROR, no sampler instance to handle bank select LSB."
379                          << "This is a bug, please report it!\n" << std::flush;
380                return;
381            }
382            const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
383            // dispatch event for engines listening to the same MIDI channel
384            {
385                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
386                std::set<EngineChannel*>::iterator end        = midiChannelMap[MidiChannel].end();
387                // according to the MIDI specs, a bank select should not alter the patch
388                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
389            }
390            // dispatch event for engines listening to ALL MIDI channels
391            {
392                std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
393                std::set<EngineChannel*>::iterator end        = midiChannelMap[midi_chan_all].end();
394                // according to the MIDI specs, a bank select should not alter the patch
395                for (; engineiter != end; engineiter++) (*engineiter)->SetMidiBankLsb(BankLSB);
396            }
397            MidiChannelMapReader.Unlock();
398        }
399    
400          // now connect to the new engine channel and remember it      void MidiInputPort::DispatchRaw(uint8_t* pData) {
401          try {          uint8_t channel = pData[0] & 0x0f;
402              Connect(pEngineChannel, (midi_chan_t) MidiChannel);          switch (pData[0] & 0xf0) {
403              pPreviousProgramChangeEngineChannel = pEngineChannel;          case 0x80:
404                DispatchNoteOff(pData[1], pData[2], channel);
405                break;
406            case 0x90:
407                if (pData[2]) {
408                    DispatchNoteOn(pData[1], pData[2], channel);
409                } else {
410                    DispatchNoteOff(pData[1], pData[2], channel);
411                }
412                break;
413            case 0xb0:
414                if (pData[1] == 0) {
415                    DispatchBankSelectMsb(pData[2], channel);
416                } else if (pData[1] == 32) {
417                    DispatchBankSelectLsb(pData[2], channel);
418                }
419                DispatchControlChange(pData[1], pData[2], channel);
420                break;
421            case 0xc0:
422                DispatchProgramChange(pData[1], channel);
423                break;
424            case 0xd0:
425                DispatchControlChange(128, pData[1], channel);
426                break;
427            case 0xe0:
428                DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel);
429                break;
430            }
431        }
432    
433        void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) {
434            uint8_t channel = pData[0] & 0x0f;
435            switch (pData[0] & 0xf0) {
436            case 0x80:
437                DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
438                break;
439            case 0x90:
440                if (pData[2]) {
441                    DispatchNoteOn(pData[1], pData[2], channel, FragmentPos);
442                } else {
443                    DispatchNoteOff(pData[1], pData[2], channel, FragmentPos);
444                }
445                break;
446            case 0xb0:
447                if (pData[1] == 0) {
448                    DispatchBankSelectMsb(pData[2], channel);
449                } else if (pData[1] == 32) {
450                    DispatchBankSelectLsb(pData[2], channel);
451                }
452                DispatchControlChange(pData[1], pData[2], channel, FragmentPos);
453                break;
454            case 0xc0:
455                DispatchProgramChange(pData[1], channel);
456                break;
457            case 0xd0:
458                DispatchControlChange(128, pData[1], channel, FragmentPos);
459                break;
460            case 0xe0:
461                DispatchPitchbend((pData[1] | pData[2] << 7) - 8192, channel, FragmentPos);
462                break;
463          }          }
         catch (...) { /* NOOP */ }  
464      }      }
465    
466      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
# Line 344  namespace LinuxSampler { Line 537  namespace LinuxSampler {
537          return count;          return count;
538      }      }
539    
540        void MidiInputPort::Connect(VirtualMidiDevice* pDevice) {
541            virtualMidiDevicesMutex.Lock();
542            // double buffer ... double work ...
543            {
544                std::vector<VirtualMidiDevice*>& devices =
545                    virtualMidiDevices.GetConfigForUpdate();
546                devices.push_back(pDevice);
547            }
548            {
549                std::vector<VirtualMidiDevice*>& devices =
550                    virtualMidiDevices.SwitchConfig();
551                devices.push_back(pDevice);
552            }
553            virtualMidiDevicesMutex.Unlock();
554        }
555    
556        void MidiInputPort::Disconnect(VirtualMidiDevice* pDevice) {
557            virtualMidiDevicesMutex.Lock();
558            // double buffer ... double work ...
559            {
560                std::vector<VirtualMidiDevice*>& devices =
561                    virtualMidiDevices.GetConfigForUpdate();
562                devices.erase(std::find(devices.begin(), devices.end(), pDevice));
563            }
564            {
565                std::vector<VirtualMidiDevice*>& devices =
566                    virtualMidiDevices.SwitchConfig();
567                devices.erase(std::find(devices.begin(), devices.end(), pDevice));
568            }
569            virtualMidiDevicesMutex.Unlock();
570        }
571    
572  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.922  
changed lines
  Added in v.1887

  ViewVC Help
Powered by ViewVC