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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 840 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 Christian Schoenebeck *
7 * *
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 #include "../../Sampler.h"
27 #include "../../engines/EngineFactory.h"
28
29 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 Parameters.clear();
70 }
71
72 MidiInputPort::MidiInputPort(MidiInputDevice* pDevice, int portNumber) {
73 this->pDevice = pDevice;
74 this->portNumber = portNumber;
75 Parameters["NAME"] = new ParameterName(this);
76 pPreviousProgramChangeEngineChannel = NULL;
77 }
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 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
93 // dispatch event for engines listening to the same MIDI channel
94 {
95 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
96 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
97 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
98 }
99 // dispatch event for engines listening to ALL MIDI channels
100 {
101 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
102 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
103 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOn(Key, Velocity);
104 }
105 MidiChannelMap.Unlock();
106 }
107
108 void MidiInputPort::DispatchNoteOff(uint8_t Key, uint8_t Velocity, uint MidiChannel) {
109 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
110 // dispatch event for engines listening to the same MIDI channel
111 {
112 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
113 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
114 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
115 }
116 // dispatch event for engines listening to ALL MIDI channels
117 {
118 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
119 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
120 for (; engineiter != end; engineiter++) (*engineiter)->SendNoteOff(Key, Velocity);
121 }
122 MidiChannelMap.Unlock();
123 }
124
125 void MidiInputPort::DispatchPitchbend(int Pitch, uint MidiChannel) {
126 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
127 // dispatch event for engines listening to the same MIDI channel
128 {
129 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
130 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
131 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
132 }
133 // dispatch event for engines listening to ALL MIDI channels
134 {
135 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
136 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
137 for (; engineiter != end; engineiter++) (*engineiter)->SendPitchbend(Pitch);
138 }
139 MidiChannelMap.Unlock();
140 }
141
142 void MidiInputPort::DispatchControlChange(uint8_t Controller, uint8_t Value, uint MidiChannel) {
143 const MidiChannelMap_t& midiChannelMap = MidiChannelMap.Lock();
144 // dispatch event for engines listening to the same MIDI channel
145 {
146 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[MidiChannel].begin();
147 std::set<EngineChannel*>::iterator end = midiChannelMap[MidiChannel].end();
148 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
149 }
150 // dispatch event for engines listening to ALL MIDI channels
151 {
152 std::set<EngineChannel*>::iterator engineiter = midiChannelMap[midi_chan_all].begin();
153 std::set<EngineChannel*>::iterator end = midiChannelMap[midi_chan_all].end();
154 for (; engineiter != end; engineiter++) (*engineiter)->SendControlChange(Controller, Value);
155 }
156 MidiChannelMap.Unlock();
157 }
158
159 void MidiInputPort::DispatchSysex(void* pData, uint Size) {
160 // 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 }
165
166 void MidiInputPort::DispatchProgramChange(uint8_t Program, uint MidiChannel) {
167 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
184 // 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 void MidiInputPort::Connect(EngineChannel* pEngineChannel, midi_chan_t MidiChannel) {
193 if (MidiChannel < 0 || MidiChannel > 16)
194 throw MidiInputException("MIDI channel index out of bounds");
195
196 // first check if desired connection is already established
197 MidiChannelMapMutex.Lock();
198 MidiChannelMap_t& midiChannelMap = MidiChannelMap.GetConfigForUpdate();
199 bool bAlreadyDone = midiChannelMap[MidiChannel].count(pEngineChannel);
200 MidiChannelMapMutex.Unlock();
201 if (bAlreadyDone) return;
202
203 // remove all other connections of that engine channel (if any)
204 Disconnect(pEngineChannel);
205
206 // register engine channel on the desired MIDI channel
207 MidiChannelMapMutex.Lock();
208 MidiChannelMap.GetConfigForUpdate()[MidiChannel].insert(pEngineChannel);
209 MidiChannelMap.SwitchConfig()[MidiChannel].insert(pEngineChannel);
210 MidiChannelMapMutex.Unlock();
211
212 // inform engine channel about this connection
213 pEngineChannel->Connect(this, MidiChannel);
214
215 // mark engine channel as changed
216 pEngineChannel->StatusChanged(true);
217 }
218
219 void MidiInputPort::Disconnect(EngineChannel* pEngineChannel) {
220 if (!pEngineChannel) return;
221
222 bool bChannelFound = false;
223
224 // unregister engine channel from all MIDI channels
225 MidiChannelMapMutex.Lock();
226 try {
227 {
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 }
234 // 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 }
243 catch(...) { /* NOOP */ }
244 MidiChannelMapMutex.Unlock();
245
246 // inform engine channel about the disconnection (if there is one)
247 if (bChannelFound) pEngineChannel->DisconnectMidiInputPort();
248
249 // mark engine channel as changed
250 pEngineChannel->StatusChanged(true);
251 }
252
253 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC