/[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 3054 - (show annotations) (download)
Thu Dec 15 12:47:45 2016 UTC (7 years, 4 months ago) by schoenebeck
File size: 18898 byte(s)
* Fixed numerous compiler warnings.
* Bumped version (2.0.0.svn32).

1 /***************************************************************************
2 * *
3 * Copyright (C) 2006 - 2016 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/global_private.h"
24 #include "../../common/Mutex.h"
25 #include "../../engines/EngineFactory.h"
26 #include "../../engines/Engine.h"
27
28 #if AC_APPLE_UNIVERSAL_BUILD
29 # include <libgig/RIFF.h>
30 #else
31 # include <RIFF.h>
32 #endif
33
34 namespace LinuxSampler {
35
36 // same as entry_t but without 'LoadMode'
37 struct private_entry_t {
38 String EngineName;
39 String InstrumentFile;
40 uint InstrumentIndex;
41 float Volume;
42 String Name;
43 };
44
45 // internal map type (MIDI bank&prog) -> (Engine,File,Index)
46 class MidiInstrumentMap : public std::map<midi_prog_index_t,private_entry_t> {
47 public:
48 String name;
49 };
50
51 // here we store all maps
52 std::map<int,MidiInstrumentMap> midiMaps;
53
54 // for synchronization of midiMaps
55 Mutex midiMapsMutex;
56
57 ListenerList<MidiInstrumentCountListener*> MidiInstrumentMapper::llMidiInstrumentCountListeners;
58 ListenerList<MidiInstrumentInfoListener*> MidiInstrumentMapper::llMidiInstrumentInfoListeners;
59 ListenerList<MidiInstrumentMapCountListener*> MidiInstrumentMapper::llMidiInstrumentMapCountListeners;
60 ListenerList<MidiInstrumentMapInfoListener*> MidiInstrumentMapper::llMidiInstrumentMapInfoListeners;
61 int MidiInstrumentMapper::DefaultMap;
62
63 void MidiInstrumentMapper::AddMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
64 llMidiInstrumentCountListeners.AddListener(l);
65 }
66
67 void MidiInstrumentMapper::RemoveMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
68 llMidiInstrumentCountListeners.RemoveListener(l);
69 }
70
71 void MidiInstrumentMapper::fireMidiInstrumentCountChanged(int MapId, int NewCount) {
72 for (int i = 0; i < llMidiInstrumentCountListeners.GetListenerCount(); i++) {
73 llMidiInstrumentCountListeners.GetListener(i)->MidiInstrumentCountChanged(MapId, NewCount);
74 }
75 }
76
77 void MidiInstrumentMapper::AddMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
78 llMidiInstrumentInfoListeners.AddListener(l);
79 }
80
81 void MidiInstrumentMapper::RemoveMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
82 llMidiInstrumentInfoListeners.RemoveListener(l);
83 }
84
85 void MidiInstrumentMapper::fireMidiInstrumentInfoChanged(int MapId, int Bank, int Program) {
86 for (int i = 0; i < llMidiInstrumentInfoListeners.GetListenerCount(); i++) {
87 llMidiInstrumentInfoListeners.GetListener(i)->MidiInstrumentInfoChanged(MapId, Bank, Program);
88 }
89 }
90
91 void MidiInstrumentMapper::AddMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
92 llMidiInstrumentMapCountListeners.AddListener(l);
93 }
94
95 void MidiInstrumentMapper::RemoveMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
96 llMidiInstrumentMapCountListeners.RemoveListener(l);
97 }
98
99 void MidiInstrumentMapper::fireMidiInstrumentMapCountChanged(int NewCount) {
100 for (int i = 0; i < llMidiInstrumentMapCountListeners.GetListenerCount(); i++) {
101 llMidiInstrumentMapCountListeners.GetListener(i)->MidiInstrumentMapCountChanged(NewCount);
102 }
103 }
104
105 void MidiInstrumentMapper::AddMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
106 llMidiInstrumentMapInfoListeners.AddListener(l);
107 }
108
109 void MidiInstrumentMapper::RemoveMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
110 llMidiInstrumentMapInfoListeners.RemoveListener(l);
111 }
112
113 void MidiInstrumentMapper::fireMidiInstrumentMapInfoChanged(int MapId) {
114 for (int i = 0; i < llMidiInstrumentMapInfoListeners.GetListenerCount(); i++) {
115 llMidiInstrumentMapInfoListeners.GetListener(i)->MidiInstrumentMapInfoChanged(MapId);
116 }
117 }
118
119 void MidiInstrumentMapper::AddOrReplaceEntry(int Map, midi_prog_index_t Index, entry_t Entry, bool bInBackground) throw (Exception) {
120 if (bInBackground) {
121 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d in background\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 } else {
128 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d\n",
129 Map,
130 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
131 Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
132 Entry.Volume,Entry.LoadMode)
133 );
134 }
135 {
136 LockGuard lock(midiMapsMutex);
137 if (midiMaps.empty()) {
138 throw Exception("There is no MIDI instrument map, you have to add one first.");
139 }
140 }
141 if (!Entry.InstrumentFile.size())
142 throw Exception("No instrument file name given");
143 // TODO: an easy one - we should check here if given file exists and throw an exception if it doesn't
144 if (Entry.Volume < 0.0)
145 throw Exception("Volume may not be a negative value");
146 Engine* pEngine = EngineFactory::Create(Entry.EngineName);
147 if (!pEngine)
148 throw Exception("No such engine type '"+Entry.EngineName+"'");
149 Entry.EngineName = pEngine->EngineName(); // make sure to use the official engine name
150 if (pEngine->GetInstrumentManager()) {
151 InstrumentManager::instrument_id_t id;
152 id.FileName = Entry.InstrumentFile;
153 id.Index = Entry.InstrumentIndex;
154 if (Entry.LoadMode != DONTCARE) {
155 if (bInBackground)
156 pEngine->GetInstrumentManager()->SetModeInBackground(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
157 else
158 try { pEngine->GetInstrumentManager()->SetMode(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode)); }
159 catch (RIFF::Exception e) { throw Exception(e.Message); }
160 }
161 } else {
162 dmsg(1,("WARNING: no InstrumentManager for engine '%s'\n",Entry.EngineName.c_str()));
163 }
164 private_entry_t privateEntry;
165 privateEntry.EngineName = Entry.EngineName;
166 privateEntry.InstrumentFile = Entry.InstrumentFile;
167 privateEntry.InstrumentIndex = Entry.InstrumentIndex;
168 privateEntry.Volume = Entry.Volume;
169 privateEntry.Name = Entry.Name;
170
171 bool Replaced = false;
172 int InstrCount = 0;
173 bool MapFound = false;
174 {
175 LockGuard lock(midiMapsMutex);
176 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
177 if (iterMap != midiMaps.end()) { // map found
178 MapFound = true;
179 Replaced = (iterMap->second.find(Index) != iterMap->second.end());
180 iterMap->second[Index] = privateEntry;
181 InstrCount = (int)iterMap->second.size();
182 }
183 }
184 EngineFactory::Destroy(pEngine);
185 if (!MapFound) {
186 throw Exception("There is no MIDI instrument map " + ToString(Map));
187 }
188
189 if (Replaced) {
190 int Bank = (int(Index.midi_bank_msb) << 7) | int(Index.midi_bank_lsb);
191 fireMidiInstrumentInfoChanged(Map, Bank, Index.midi_prog);
192 } else {
193 fireMidiInstrumentCountChanged(Map, InstrCount);
194 }
195 }
196
197 void MidiInstrumentMapper::SetLoadMode(entry_t* pEntry) {
198 Engine* pEngine = EngineFactory::Create(pEntry->EngineName);
199 if (!pEngine) { // invalid mapping
200 throw Exception("Invalid mapping");
201 }
202
203 InstrumentManager* pManager = pEngine->GetInstrumentManager();
204 if (pManager) { // engine provides an InstrumentManager
205 InstrumentManager::instrument_id_t id;
206 id.FileName = pEntry->InstrumentFile;
207 id.Index = pEntry->InstrumentIndex;
208 pEntry->LoadMode = static_cast<mode_t>(pManager->GetMode(id));
209 } else { // engine does not provide an InstrumentManager
210 // use default value
211 pEntry->LoadMode = ON_DEMAND;
212 }
213
214 EngineFactory::Destroy(pEngine);
215 }
216
217 MidiInstrumentMapper::entry_t MidiInstrumentMapper::GetEntry(int Map, uint MidiBank, uint MidiProg) {
218 LockGuard lock(midiMapsMutex);
219
220 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
221 if (iterMap == midiMaps.end()) { // no such map
222 throw Exception("There is no MIDI instrument map " + ToString(Map));
223 }
224
225 midi_prog_index_t idx;
226 idx.midi_bank_msb = (MidiBank >> 7) & 0x7f;
227 idx.midi_bank_lsb = MidiBank & 0x7f;
228 idx.midi_prog = MidiProg;
229
230 std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(idx);
231 if (iterEntry == iterMap->second.end()) {
232 throw Exception("There is no map entry with that index");
233 }
234
235 entry_t entry;
236 entry.EngineName = iterEntry->second.EngineName;
237 entry.InstrumentFile = iterEntry->second.InstrumentFile;
238 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
239 entry.Volume = iterEntry->second.Volume;
240 entry.Name = iterEntry->second.Name;
241
242 try {
243 SetLoadMode(&entry);
244 } catch(Exception e) {
245 throw e;
246 }
247
248 return entry;
249 }
250
251 void MidiInstrumentMapper::RemoveEntry(int Map, midi_prog_index_t Index) {
252 int InstrCount = -1;
253 {
254 LockGuard lock(midiMapsMutex);
255
256 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
257 if (iterMap != midiMaps.end()) { // map found
258 iterMap->second.erase(Index); // remove entry
259 InstrCount = (int)iterMap->second.size();
260 }
261 }
262
263 if (InstrCount != -1) {
264 fireMidiInstrumentCountChanged(Map, InstrCount);
265 }
266 }
267
268 void MidiInstrumentMapper::RemoveAllEntries(int Map) {
269 int InstrCount = -1;
270 {
271 LockGuard lock(midiMapsMutex);
272
273 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
274 if (iterMap != midiMaps.end()) { // map found
275 iterMap->second.clear(); // clear that map
276 InstrCount = 0;
277 }
278 }
279
280 if (InstrCount != -1) {
281 fireMidiInstrumentCountChanged(Map, InstrCount);
282 }
283 }
284
285 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
286 std::map<midi_prog_index_t,entry_t> result;
287
288 // copy the internal map first
289 {
290 LockGuard lock(midiMapsMutex);
291
292 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
293 if (iterMap == midiMaps.end()) { // no such map
294 throw Exception("There is no MIDI instrument map " + ToString(Map));
295 }
296 for (std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.begin();
297 iterEntry != iterMap->second.end(); iterEntry++)
298 {
299 entry_t entry;
300 entry.EngineName = iterEntry->second.EngineName;
301 entry.InstrumentFile = iterEntry->second.InstrumentFile;
302 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
303 entry.Volume = iterEntry->second.Volume;
304 entry.Name = iterEntry->second.Name;
305 result[iterEntry->first] = entry;
306 }
307 }
308
309 // complete it with current LoadMode of each entry
310 for (std::map<midi_prog_index_t,entry_t>::iterator iter = result.begin();
311 iter != result.end(); iter++)
312 {
313 try {
314 SetLoadMode(&(iter->second));
315 } catch(Exception e) {
316 RemoveEntry(Map, iter->first);
317 result.erase(iter);
318 }
319 }
320 return result;
321 }
322
323 std::vector<int> MidiInstrumentMapper::Maps() {
324 std::vector<int> result;
325 LockGuard lock(midiMapsMutex);
326 for (std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.begin();
327 iterMap != midiMaps.end(); iterMap++)
328 {
329 result.push_back(iterMap->first);
330 }
331 return result;
332 }
333
334 int MidiInstrumentMapper::GetMapCount() {
335 LockGuard lock(midiMapsMutex);
336 return (int) midiMaps.size();
337 }
338
339 int MidiInstrumentMapper::GetInstrumentCount(int Map) {
340 LockGuard lock(midiMapsMutex);
341 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
342 if (iterMap == midiMaps.end()) { // no such map
343 throw Exception("There is no MIDI instrument map " + ToString(Map));
344 }
345
346 return (int) iterMap->second.size();
347 }
348
349 int MidiInstrumentMapper::GetInstrumentCount() {
350 int count = 0;
351
352 LockGuard lock(midiMapsMutex);
353 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.begin();
354 for (;iterMap != midiMaps.end(); iterMap++) {
355 count += iterMap->second.size();
356 }
357
358 return count;
359 }
360
361 int MidiInstrumentMapper::AddMap(String MapName) throw (Exception) {
362 int ID;
363 LockGuard lock(midiMapsMutex);
364
365 if (midiMaps.empty()) ID = 0;
366 else {
367 // get the highest existing map ID
368 uint lastIndex = (--(midiMaps.end()))->first;
369 // check if we reached the index limit
370 if (lastIndex + 1 < lastIndex) {
371 // search for an unoccupied map ID starting from 0
372 for (uint i = 0; i < lastIndex; i++) {
373 if (midiMaps.find(i) != midiMaps.end()) continue;
374 // we found an unused ID, so insert the new map there
375 ID = i;
376 goto __create_map;
377 }
378 throw Exception("Internal error: could not find unoccupied MIDI instrument map ID.");
379 }
380 ID = lastIndex + 1;
381 }
382 __create_map:
383 midiMaps[ID].name = MapName;
384
385 fireMidiInstrumentMapCountChanged((int)Maps().size());
386 // If there were no maps until now we must set a default map.
387 if (midiMaps.size() == 1) SetDefaultMap(ID);
388
389 return ID;
390 }
391
392 String MidiInstrumentMapper::MapName(int Map) throw (Exception) {
393 LockGuard lock(midiMapsMutex);
394 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
395 if (iterMap == midiMaps.end()) {
396 throw Exception("There is no MIDI instrument map " + ToString(Map));
397 }
398 return iterMap->second.name;
399 }
400
401 void MidiInstrumentMapper::RenameMap(int Map, String NewName) throw (Exception) {
402 {
403 LockGuard lock(midiMapsMutex);
404 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
405 if (iterMap == midiMaps.end()) {
406 throw Exception("There is no MIDI instrument map " + ToString(Map));
407 }
408 iterMap->second.name = NewName;
409 }
410 fireMidiInstrumentMapInfoChanged(Map);
411 }
412
413 void MidiInstrumentMapper::RemoveMap(int Map) {
414 LockGuard lock(midiMapsMutex);
415
416 midiMaps.erase(Map);
417 if (Map == GetDefaultMap()) {
418 SetDefaultMap(midiMaps.empty() ? -1 : (*(midiMaps.begin())).first);
419 }
420 fireMidiInstrumentMapCountChanged((int)Maps().size());
421 }
422
423 void MidiInstrumentMapper::RemoveAllMaps() {
424 LockGuard lock(midiMapsMutex);
425
426 midiMaps.clear();
427 SetDefaultMap(-1);
428 fireMidiInstrumentMapCountChanged((int)Maps().size());
429 }
430
431 int MidiInstrumentMapper::GetDefaultMap() {
432 LockGuard lock(midiMapsMutex);
433
434 return DefaultMap;
435 }
436
437 void MidiInstrumentMapper::SetDefaultMap(int MapId) {
438 {
439 LockGuard lock(midiMapsMutex);
440
441 DefaultMap = MapId;
442 }
443
444 if (MapId != -1) fireMidiInstrumentMapInfoChanged(MapId);
445 }
446
447 optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
448 optional<entry_t> result;
449 LockGuard lock(midiMapsMutex);
450
451 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
452 if (iterMap != midiMaps.end()) { // map found
453 std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(Index);
454 if (iterEntry != iterMap->second.end()) {
455 entry_t entry;
456 entry.EngineName = iterEntry->second.EngineName;
457 entry.InstrumentFile = iterEntry->second.InstrumentFile;
458 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
459 entry.Volume = iterEntry->second.Volume;
460 //TODO: for now we skip the LoadMode and Name entry here, since we don't need it in the EngineChannel
461 result = entry;
462 }
463 }
464 return result;
465 }
466
467 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC