/[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 840 - (hide annotations) (download)
Sun Feb 26 13:00:08 2006 UTC (18 years, 1 month ago) by persson
File size: 11322 byte(s)
* fixed some concurrency problems between the lscp thread and the
  audio/midi threads for these commands: load engine, set channel
  audio output device, set channel midi input device/port/channel and
  remove channel. Thanks to Vincent Bongiorno for bug reports and
  testing.
* removed an autotools warning
* fixed an iterator bug
* minor code clean-ups

1 schoenebeck 221 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 411 * Copyright (C) 2005 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     void MidiInputPort::ParameterName::OnSetValue(String s) throw (LinuxSamplerException) {
55     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     MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber) {
73     this->pDevice = pDevice;
74     this->portNumber = portNumber;
75     Parameters["NAME"] = new ParameterName(this);
76 schoenebeck 551 pPreviousProgramChangeEngineChannel = NULL;
77 schoenebeck 221 }
78    
79     MidiInputDevice* MidiInputPort::GetDevice() {
80     return pDevice;
81     }
82    
83     uint MidiInputPort::GetPortNumber() {
84     return portNumber;
85     }
86    
87     std::map<String,DeviceRuntimeParameter*> MidiInputPort::PortParameters() {
88     return Parameters;
89     }
90    
91     void MidiInputPort::DispatchNoteOn(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
92 persson 840 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
93 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
94     {
95 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
96     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
97 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
98     }
99     // dispatch event for engines listening to ALL MIDI channels
100     {
101 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
102     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
103 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
104     }
105 persson 840 MidiChannelMap.Unlock();
106 schoenebeck 221 }
107    
108     void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
109 persson 840 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
110 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
111     {
112 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
113     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
114 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
115     }
116     // dispatch event for engines listening to ALL MIDI channels
117     {
118 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
119     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
120 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
121     }
122 persson 840 MidiChannelMap.Unlock();
123 schoenebeck 221 }
124    
125     void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
126 persson 840 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
127 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
128     {
129 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
130     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
131 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
132     }
133     // dispatch event for engines listening to ALL MIDI channels
134     {
135 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
136     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
137 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
138     }
139 persson 840 MidiChannelMap.Unlock();
140 schoenebeck 221 }
141    
142     void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
143 persson 840 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
144 schoenebeck 274 // dispatch event for engines listening to the same MIDI channel
145     {
146 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
147     std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
148 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
149     }
150     // dispatch event for engines listening to ALL MIDI channels
151     {
152 persson 840 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
153     std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
154 schoenebeck 274 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
155     }
156 persson 840 MidiChannelMap.Unlock();
157 schoenebeck 221 }
158    
159 schoenebeck 244 void MidiInputPort::DispatchSysex(void* pData, uint Size) {
160 schoenebeck 775 // dispatch event to all engine instances
161     std::set<Engine*>::iterator engineiter = EngineFactory::EngineInstances().begin();
162     std::set<Engine*>::iterator end = EngineFactory::EngineInstances().end();
163     for (; engineiter != end; engineiter++) (*engineiter)->SendSysex(pData, Size);
164 schoenebeck 244 }
165    
166 schoenebeck 670 void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
167 schoenebeck 551 if (!pDevice || !pDevice->pSampler) {
168     std::cerr << "MidiInputPort: ERROR, no sampler instance to handle program change."
169     << "This is a bug, please report it!\n" << std::flush;
170     return;
171     }
172    
173     Sampler* pSampler = (Sampler*) pDevice->pSampler;
174     SamplerChannel* pSamplerChannel = pSampler->GetSamplerChannel(Program);
175     if (!pSamplerChannel) return;
176    
177     EngineChannel* pEngineChannel = pSamplerChannel->GetEngineChannel();
178     if (!pEngineChannel) return;
179    
180     // disconnect from the engine channel which was connected by the last PC event
181     if (pPreviousProgramChangeEngineChannel)
182     Disconnect(pPreviousProgramChangeEngineChannel);
183 schoenebeck 670
184 schoenebeck 551 // now connect to the new engine channel and remember it
185     try {
186     Connect(pEngineChannel, (midi_chan_t) MidiChannel);
187     pPreviousProgramChangeEngineChannel = pEngineChannel;
188     }
189     catch (...) { /* NOOP */ }
190     }
191    
192 schoenebeck 411 void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
193 schoenebeck 221 if (MidiChannel < 0 || MidiChannel > 16)
194     throw MidiInputException("MIDI channel index out of bounds");
195 schoenebeck 670
196 persson 840 // first check if desired connection is already established
197 schoenebeck 675 MidiChannelMapMutex.Lock();
198 persson 840 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
199     bool bAlreadyDone = midiChannelMap[MidiChannel].count(pEngineChannel);
200 schoenebeck 675 MidiChannelMapMutex.Unlock();
201     if (bAlreadyDone) return;
202    
203     // remove all other connections of that engine channel (if any)
204 schoenebeck 411 Disconnect(pEngineChannel);
205 schoenebeck 670
206 schoenebeck 675 // register engine channel on the desired MIDI channel
207 schoenebeck 551 MidiChannelMapMutex.Lock();
208 persson 840 MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
209     MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
210 schoenebeck 551 MidiChannelMapMutex.Unlock();
211 schoenebeck 670
212 schoenebeck 675 // inform engine channel about this connection
213     pEngineChannel->Connect(this, MidiChannel);
214    
215 schoenebeck 670 // mark engine channel as changed
216     pEngineChannel->StatusChanged(true);
217 schoenebeck 221 }
218    
219 schoenebeck 411 void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) {
220 schoenebeck 675 if (!pEngineChannel) return;
221    
222     bool bChannelFound = false;
223    
224     // unregister engine channel from all MIDI channels
225 schoenebeck 551 MidiChannelMapMutex.Lock();
226 schoenebeck 675 try {
227 persson 840 {
228     MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
229     for (int i = 0; i <= 16; i++) {
230     bChannelFound |= midiChannelMap[i].count(pEngineChannel);
231     midiChannelMap[i].erase(pEngineChannel);
232     }
233 schoenebeck 675 }
234 persson 840 // do the same update again, after switching to the other config
235     {
236     MidiChannelMap_t& midiChannelMap = MidiChannelMap.SwitchConfig();
237     for (int i = 0; i <= 16; i++) {
238     bChannelFound |= midiChannelMap[i].count(pEngineChannel);
239     midiChannelMap[i].erase(pEngineChannel);
240     }
241     }
242 schoenebeck 675 }
243 schoenebeck 221 catch(...) { /* NOOP */ }
244 schoenebeck 551 MidiChannelMapMutex.Unlock();
245 schoenebeck 675
246     // inform engine channel about the disconnection (if there is one)
247     if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();
248    
249 schoenebeck 670 // mark engine channel as changed
250     pEngineChannel->StatusChanged(true);
251 schoenebeck 221 }
252    
253     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC