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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1135 - (show annotations) (download)
Thu Mar 29 09:40:45 2007 UTC (17 years ago) by iliev
File size: 16828 byte(s)
* Added new LSCP command - SET FX_SEND NAME
* The default map is now the first available map

1 /***************************************************************************
2 * *
3 * Copyright (C) 2006 - 2007 Christian Schoenebeck *
4 * *
5 * This library is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This library is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this library; if not, write to the Free Software *
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
18 * MA 02111-1307 USA *
19 ***************************************************************************/
20
21 #include "MidiInstrumentMapper.h"
22
23 #include "../../common/Mutex.h"
24 #include "../../engines/EngineFactory.h"
25 #include "../../engines/Engine.h"
26
27 namespace LinuxSampler {
28
29 // same as entry_t but without 'LoadMode'
30 struct private_entry_t {
31 String EngineName;
32 String InstrumentFile;
33 uint InstrumentIndex;
34 float Volume;
35 String Name;
36 };
37
38 // internal map type (MIDI bank&prog) -> (Engine,File,Index)
39 class MidiInstrumentMap : public std::map<midi_prog_index_t,private_entry_t> {
40 public:
41 String name;
42 };
43
44 // here we store all maps
45 std::map<int,MidiInstrumentMap> midiMaps;
46
47 // for synchronization of midiMaps
48 Mutex midiMapsMutex;
49
50 ListenerList<MidiInstrumentCountListener*> MidiInstrumentMapper::llMidiInstrumentCountListeners;
51 ListenerList<MidiInstrumentInfoListener*> MidiInstrumentMapper::llMidiInstrumentInfoListeners;
52 ListenerList<MidiInstrumentMapCountListener*> MidiInstrumentMapper::llMidiInstrumentMapCountListeners;
53 ListenerList<MidiInstrumentMapInfoListener*> MidiInstrumentMapper::llMidiInstrumentMapInfoListeners;
54 int MidiInstrumentMapper::DefaultMap;
55
56 void MidiInstrumentMapper::AddMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
57 llMidiInstrumentCountListeners.AddListener(l);
58 }
59
60 void MidiInstrumentMapper::RemoveMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
61 llMidiInstrumentCountListeners.RemoveListener(l);
62 }
63
64 void MidiInstrumentMapper::fireMidiInstrumentCountChanged(int MapId, int NewCount) {
65 for (int i = 0; i < llMidiInstrumentCountListeners.GetListenerCount(); i++) {
66 llMidiInstrumentCountListeners.GetListener(i)->MidiInstrumentCountChanged(MapId, NewCount);
67 }
68 }
69
70 void MidiInstrumentMapper::AddMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
71 llMidiInstrumentInfoListeners.AddListener(l);
72 }
73
74 void MidiInstrumentMapper::RemoveMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
75 llMidiInstrumentInfoListeners.RemoveListener(l);
76 }
77
78 void MidiInstrumentMapper::fireMidiInstrumentInfoChanged(int MapId, int Bank, int Program) {
79 for (int i = 0; i < llMidiInstrumentInfoListeners.GetListenerCount(); i++) {
80 llMidiInstrumentInfoListeners.GetListener(i)->MidiInstrumentInfoChanged(MapId, Bank, Program);
81 }
82 }
83
84 void MidiInstrumentMapper::AddMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
85 llMidiInstrumentMapCountListeners.AddListener(l);
86 }
87
88 void MidiInstrumentMapper::RemoveMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
89 llMidiInstrumentMapCountListeners.RemoveListener(l);
90 }
91
92 void MidiInstrumentMapper::fireMidiInstrumentMapCountChanged(int NewCount) {
93 for (int i = 0; i < llMidiInstrumentMapCountListeners.GetListenerCount(); i++) {
94 llMidiInstrumentMapCountListeners.GetListener(i)->MidiInstrumentMapCountChanged(NewCount);
95 }
96 }
97
98 void MidiInstrumentMapper::AddMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
99 llMidiInstrumentMapInfoListeners.AddListener(l);
100 }
101
102 void MidiInstrumentMapper::RemoveMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
103 llMidiInstrumentMapInfoListeners.RemoveListener(l);
104 }
105
106 void MidiInstrumentMapper::fireMidiInstrumentMapInfoChanged(int MapId) {
107 for (int i = 0; i < llMidiInstrumentMapInfoListeners.GetListenerCount(); i++) {
108 llMidiInstrumentMapInfoListeners.GetListener(i)->MidiInstrumentMapInfoChanged(MapId);
109 }
110 }
111
112 void MidiInstrumentMapper::AddOrReplaceEntry(int Map, midi_prog_index_t Index, entry_t Entry, bool bInBackground) throw (Exception) {
113 if (bInBackground) {
114 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d in background\n",
115 Map,
116 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
117 Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
118 Entry.Volume,Entry.LoadMode)
119 );
120 } else {
121 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d\n",
122 Map,
123 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
124 Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
125 Entry.Volume,Entry.LoadMode)
126 );
127 }
128 midiMapsMutex.Lock();
129 if (midiMaps.empty()) {
130 midiMapsMutex.Unlock();
131 throw Exception("There is no MIDI instrument map, you have to add one first.");
132 }
133 midiMapsMutex.Unlock();
134 if (!Entry.InstrumentFile.size())
135 throw Exception("No instrument file name given");
136 // TODO: an easy one - we should check here if given file exists and throw an exception if it doesn't
137 if (Entry.Volume < 0.0)
138 throw Exception("Volume may not be a negative value");
139 Engine* pEngine = EngineFactory::Create(Entry.EngineName);
140 if (!pEngine)
141 throw Exception("No such engine type '"+Entry.EngineName+"'");
142 Entry.EngineName = pEngine->EngineName(); // make sure to use the official engine name
143 if (pEngine->GetInstrumentManager()) {
144 InstrumentManager::instrument_id_t id;
145 id.FileName = Entry.InstrumentFile;
146 id.Index = Entry.InstrumentIndex;
147 if (Entry.LoadMode != VOID) {
148 if (bInBackground)
149 pEngine->GetInstrumentManager()->SetModeInBackground(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
150 else
151 pEngine->GetInstrumentManager()->SetMode(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
152 }
153 } else {
154 dmsg(1,("WARNING: no InstrumentManager for engine '%s'\n",Entry.EngineName.c_str()));
155 }
156 private_entry_t privateEntry;
157 privateEntry.EngineName = Entry.EngineName;
158 privateEntry.InstrumentFile = Entry.InstrumentFile;
159 privateEntry.InstrumentIndex = Entry.InstrumentIndex;
160 privateEntry.Volume = Entry.Volume;
161 privateEntry.Name = Entry.Name;
162
163 bool Replaced = false;
164 int InstrCount = 0;
165
166 midiMapsMutex.Lock();
167 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
168 if (iterMap != midiMaps.end()) { // map found
169 Replaced = (iterMap->second.find(Index) != iterMap->second.end());
170 iterMap->second[Index] = privateEntry;
171 InstrCount = iterMap->second.size();
172 } else { // no such map
173 midiMapsMutex.Unlock();
174 EngineFactory::Destroy(pEngine);
175 throw Exception("There is no MIDI instrument map " + ToString(Map));
176 }
177 midiMapsMutex.Unlock();
178 EngineFactory::Destroy(pEngine);
179
180 if (Replaced) {
181 int Bank = (int(Index.midi_bank_msb) << 7) & int(Index.midi_bank_lsb);
182 fireMidiInstrumentInfoChanged(Map, Bank, Index.midi_prog);
183 } else {
184 fireMidiInstrumentCountChanged(Map, InstrCount);
185 }
186 }
187
188 void MidiInstrumentMapper::RemoveEntry(int Map, midi_prog_index_t Index) {
189 int InstrCount = -1;
190
191 midiMapsMutex.Lock();
192 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
193 if (iterMap != midiMaps.end()) { // map found
194 iterMap->second.erase(Index); // remove entry
195 InstrCount = iterMap->second.size();
196 }
197 midiMapsMutex.Unlock();
198
199 if (InstrCount != -1) {
200 fireMidiInstrumentCountChanged(Map, InstrCount);
201 }
202 }
203
204 void MidiInstrumentMapper::RemoveAllEntries(int Map) {
205 int InstrCount = -1;
206
207 midiMapsMutex.Lock();
208 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
209 if (iterMap != midiMaps.end()) { // map found
210 iterMap->second.clear(); // clear that map
211 InstrCount = 0;
212 }
213 midiMapsMutex.Unlock();
214
215 if (InstrCount != -1) {
216 fireMidiInstrumentCountChanged(Map, InstrCount);
217 }
218 }
219
220 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
221 std::map<midi_prog_index_t,entry_t> result;
222
223 // copy the internal map first
224 midiMapsMutex.Lock();
225 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
226 if (iterMap == midiMaps.end()) { // no such map
227 midiMapsMutex.Unlock();
228 throw Exception("There is no MIDI instrument map " + ToString(Map));
229 }
230 for (std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.begin();
231 iterEntry != iterMap->second.end(); iterEntry++)
232 {
233 entry_t entry;
234 entry.EngineName = iterEntry->second.EngineName;
235 entry.InstrumentFile = iterEntry->second.InstrumentFile;
236 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
237 entry.Volume = iterEntry->second.Volume;
238 entry.Name = iterEntry->second.Name;
239 result[iterEntry->first] = entry;
240 }
241 midiMapsMutex.Unlock();
242
243 // complete it with current LoadMode of each entry
244 for (std::map<midi_prog_index_t,entry_t>::iterator iter = result.begin();
245 iter != result.end(); iter++)
246 {
247 entry_t& entry = iter->second;
248 Engine* pEngine = EngineFactory::Create(entry.EngineName);
249 if (!pEngine) { // invalid mapping
250 RemoveEntry(Map, iter->first);
251 result.erase(iter);
252 continue;
253 }
254 InstrumentManager* pManager = pEngine->GetInstrumentManager();
255 if (pManager) { // engine provides an InstrumentManager
256 InstrumentManager::instrument_id_t id;
257 id.FileName = entry.InstrumentFile;
258 id.Index = entry.InstrumentIndex;
259 entry.LoadMode = static_cast<mode_t>(pManager->GetMode(id));
260 } else { // engine does not provide an InstrumentManager
261 // use default value
262 entry.LoadMode = ON_DEMAND;
263 }
264 EngineFactory::Destroy(pEngine);
265 }
266 return result;
267 }
268
269 std::vector<int> MidiInstrumentMapper::Maps() {
270 std::vector<int> result;
271 midiMapsMutex.Lock();
272 for (std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.begin();
273 iterMap != midiMaps.end(); iterMap++)
274 {
275 result.push_back(iterMap->first);
276 }
277 midiMapsMutex.Unlock();
278 return result;
279 }
280
281 int MidiInstrumentMapper::GetMapCount() {
282 midiMapsMutex.Lock();
283 int i = midiMaps.size();
284 midiMapsMutex.Unlock();
285 return i;
286 }
287
288 int MidiInstrumentMapper::AddMap(String MapName) throw (Exception) {
289 int ID;
290 midiMapsMutex.Lock();
291 if (midiMaps.empty()) ID = 0;
292 else {
293 // get the highest existing map ID
294 uint lastIndex = (--(midiMaps.end()))->first;
295 // check if we reached the index limit
296 if (lastIndex + 1 < lastIndex) {
297 // search for an unoccupied map ID starting from 0
298 for (uint i = 0; i < lastIndex; i++) {
299 if (midiMaps.find(i) != midiMaps.end()) continue;
300 // we found an unused ID, so insert the new map there
301 ID = i;
302 goto __create_map;
303 }
304 throw Exception("Internal error: could not find unoccupied MIDI instrument map ID.");
305 }
306 ID = lastIndex + 1;
307 }
308 __create_map:
309 midiMaps[ID].name = MapName;
310
311 fireMidiInstrumentMapCountChanged(Maps().size());
312 // If there were no maps until now we must set a default map.
313 if (midiMaps.size() == 1) SetDefaultMap(ID);
314 midiMapsMutex.Unlock();
315
316 return ID;
317 }
318
319 String MidiInstrumentMapper::MapName(int Map) throw (Exception) {
320 String result;
321 midiMapsMutex.Lock();
322 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
323 if (iterMap == midiMaps.end()) {
324 midiMapsMutex.Unlock();
325 throw Exception("There is no MIDI instrument map " + ToString(Map));
326 }
327 result = iterMap->second.name;
328 midiMapsMutex.Unlock();
329 return result;
330 }
331
332 void MidiInstrumentMapper::RenameMap(int Map, String NewName) throw (Exception) {
333 midiMapsMutex.Lock();
334 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
335 if (iterMap == midiMaps.end()) {
336 midiMapsMutex.Unlock();
337 throw Exception("There is no MIDI instrument map " + ToString(Map));
338 }
339 iterMap->second.name = NewName;
340 midiMapsMutex.Unlock();
341 fireMidiInstrumentMapInfoChanged(Map);
342 }
343
344 void MidiInstrumentMapper::RemoveMap(int Map) {
345 midiMapsMutex.Lock();
346 midiMaps.erase(Map);
347 if(Map == GetDefaultMap()) {
348 SetDefaultMap(midiMaps.empty() ? -1 : (*(midiMaps.begin())).first);
349 }
350 fireMidiInstrumentMapCountChanged(Maps().size());
351 midiMapsMutex.Unlock();
352 }
353
354 void MidiInstrumentMapper::RemoveAllMaps() {
355 midiMapsMutex.Lock();
356 midiMaps.clear();
357 SetDefaultMap(-1);
358 fireMidiInstrumentMapCountChanged(Maps().size());
359 midiMapsMutex.Unlock();
360 }
361
362 int MidiInstrumentMapper::GetDefaultMap() {
363 midiMapsMutex.Lock();
364 int i = DefaultMap;
365 midiMapsMutex.Unlock();
366 return i;
367 }
368
369 void MidiInstrumentMapper::SetDefaultMap(int MapId) {
370 midiMapsMutex.Lock();
371 DefaultMap = MapId;
372 midiMapsMutex.Unlock();
373
374 if (MapId != -1) fireMidiInstrumentMapInfoChanged(MapId);
375 }
376
377 optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
378 optional<entry_t> result;
379 midiMapsMutex.Lock();
380 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
381 if (iterMap != midiMaps.end()) { // map found
382 std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(Index);
383 if (iterEntry != iterMap->second.end()) {
384 entry_t entry;
385 entry.EngineName = iterEntry->second.EngineName;
386 entry.InstrumentFile = iterEntry->second.InstrumentFile;
387 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
388 entry.Volume = iterEntry->second.Volume;
389 //TODO: for now we skip the LoadMode and Name entry here, since we don't need it in the MidiInputPort
390 result = entry;
391 }
392 }
393 midiMapsMutex.Unlock();
394 return result;
395 }
396
397 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC