/[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 2317 by persson, Sun Feb 19 12:13:19 2012 UTC revision 2426 by schoenebeck, Fri Mar 1 23:00:17 2013 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 - 2012 Christian Schoenebeck                       *   *   Copyright (C) 2005 - 2013 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 77  namespace LinuxSampler { Line 77  namespace LinuxSampler {
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) {            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);
87      }      }
88    
# Line 97  namespace LinuxSampler { Line 100  namespace LinuxSampler {
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          if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;          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();          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          {          {
# Line 122  namespace LinuxSampler { Line 131  namespace LinuxSampler {
131    
132      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) {
133          if (Key > 127 || Velocity > 127 || MidiChannel > 16) return;          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();          const MidiChannelMap_t& midiChannelMap = MidiChannelMapReader.Lock();
141          // dispatch event for engines listening to the same MIDI channel          // dispatch event for engines listening to the same MIDI channel
142          {          {
# Line 363  namespace LinuxSampler { Line 378  namespace LinuxSampler {
378          }          }
379          MidiChannelMapReader.Unlock();          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      void MidiInputPort::DispatchRaw(uint8_t* pData) {      void MidiInputPort::DispatchRaw(uint8_t* pData) {
419            pData = handleRunningStatus(pData);
420            
421          uint8_t channel = pData[0] & 0x0f;          uint8_t channel = pData[0] & 0x0f;
422          switch (pData[0] & 0xf0) {          switch (pData[0] & 0xf0) {
423          case 0x80:          case 0x80:
# Line 398  namespace LinuxSampler { Line 451  namespace LinuxSampler {
451      }      }
452    
453      void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) {      void MidiInputPort::DispatchRaw(uint8_t* pData, int32_t FragmentPos) {
454            pData = handleRunningStatus(pData);
455            
456          uint8_t channel = pData[0] & 0x0f;          uint8_t channel = pData[0] & 0x0f;
457          switch (pData[0] & 0xf0) {          switch (pData[0] & 0xf0) {
458          case 0x80:          case 0x80:
# Line 429  namespace LinuxSampler { Line 484  namespace LinuxSampler {
484              break;              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            noteOnVelocityFilterMutex.Lock();
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            }
511            noteOnVelocityFilterMutex.Unlock();
512        }
513    
514      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {      void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
515          if (MidiChannel < 0 || MidiChannel > 16)          if (MidiChannel < 0 || MidiChannel > 16)

Legend:
Removed from v.2317  
changed lines
  Added in v.2426

  ViewVC Help
Powered by ViewVC