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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 981 - (hide annotations) (download)
Sun Dec 17 22:35:01 2006 UTC (17 years, 3 months ago) by iliev
File size: 13301 byte(s)
* Added new notification events for tracking audio/MIDI device changes,
MIDI instrument map changes and MIDI instrument changes

1 schoenebeck 947 /***************************************************************************
2     * *
3     * Copyright (C) 2006 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 iliev 981 #include "../../network/lscpserver.h"
27 schoenebeck 947
28     namespace LinuxSampler {
29    
30     // same as entry_t but without 'LoadMode'
31     struct private_entry_t {
32     String EngineName;
33     String InstrumentFile;
34     uint InstrumentIndex;
35 schoenebeck 958 float Volume;
36 schoenebeck 947 String Name;
37     };
38    
39 schoenebeck 973 // internal map type (MIDI bank&prog) -> (Engine,File,Index)
40     class MidiInstrumentMap : public std::map<midi_prog_index_t,private_entry_t> {
41     public:
42     String name;
43     };
44 schoenebeck 947
45 schoenebeck 973 // here we store all maps
46     std::map<int,MidiInstrumentMap> midiMaps;
47 schoenebeck 947
48 schoenebeck 973 // for synchronization of midiMaps
49     Mutex midiMapsMutex;
50 schoenebeck 947
51 schoenebeck 973
52     void MidiInstrumentMapper::AddOrReplaceEntry(int Map, midi_prog_index_t Index, entry_t Entry, bool bInBackground) throw (Exception) {
53 schoenebeck 947 if (bInBackground) {
54 schoenebeck 973 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d in background\n",
55     Map,
56 schoenebeck 947 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
57     Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
58     Entry.Volume,Entry.LoadMode)
59     );
60     } else {
61 schoenebeck 973 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d\n",
62     Map,
63 schoenebeck 947 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
64     Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
65     Entry.Volume,Entry.LoadMode)
66     );
67     }
68 schoenebeck 973 midiMapsMutex.Lock();
69     if (midiMaps.empty()) {
70     midiMapsMutex.Unlock();
71     throw Exception("There is no MIDI instrument map, you have to add one first.");
72     }
73     midiMapsMutex.Unlock();
74 schoenebeck 970 if (!Entry.InstrumentFile.size())
75     throw Exception("No instrument file name given");
76 schoenebeck 947 if (Entry.Volume < 0.0)
77     throw Exception("Volume may not be a negative value");
78     Engine* pEngine = EngineFactory::Create(Entry.EngineName);
79     if (!pEngine)
80     throw Exception("No such engine type '"+Entry.EngineName+"'");
81     Entry.EngineName = pEngine->EngineName(); // make sure to use the official engine name
82     if (pEngine->GetInstrumentManager()) {
83     InstrumentManager::instrument_id_t id;
84     id.FileName = Entry.InstrumentFile;
85     id.Index = Entry.InstrumentIndex;
86     if (Entry.LoadMode != VOID) {
87     if (bInBackground)
88     pEngine->GetInstrumentManager()->SetModeInBackground(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
89     else
90     pEngine->GetInstrumentManager()->SetMode(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
91     }
92     } else {
93     dmsg(1,("WARNING: no InstrumentManager for engine '%s'\n",Entry.EngineName.c_str()));
94     }
95     private_entry_t privateEntry;
96     privateEntry.EngineName = Entry.EngineName;
97     privateEntry.InstrumentFile = Entry.InstrumentFile;
98     privateEntry.InstrumentIndex = Entry.InstrumentIndex;
99 schoenebeck 958 privateEntry.Volume = Entry.Volume;
100 schoenebeck 947 privateEntry.Name = Entry.Name;
101 iliev 981
102     bool Replaced = false;
103     int InstrCount = 0;
104    
105 schoenebeck 973 midiMapsMutex.Lock();
106     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
107     if (iterMap != midiMaps.end()) { // map found
108 iliev 981 Replaced = (iterMap->second.find(Index) != iterMap->second.end());
109 schoenebeck 973 iterMap->second[Index] = privateEntry;
110 iliev 981 InstrCount = iterMap->second.size();
111 schoenebeck 973 } else { // no such map
112     midiMapsMutex.Unlock();
113     EngineFactory::Destroy(pEngine);
114     throw Exception("There is no MIDI instrument map " + ToString(Map));
115     }
116     midiMapsMutex.Unlock();
117 schoenebeck 947 EngineFactory::Destroy(pEngine);
118 iliev 981
119     if (Replaced) {
120     int Bank = (int(Index.midi_bank_msb) << 7) & int(Index.midi_bank_lsb);
121     LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_info, Map, Bank, Index.midi_prog));
122     } else {
123     LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, Map, InstrCount));
124     }
125 schoenebeck 947 }
126    
127 schoenebeck 973 void MidiInstrumentMapper::RemoveEntry(int Map, midi_prog_index_t Index) {
128 iliev 981 int InstrCount = -1;
129    
130 schoenebeck 973 midiMapsMutex.Lock();
131     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
132     if (iterMap != midiMaps.end()) { // map found
133     iterMap->second.erase(Index); // remove entry
134 iliev 981 InstrCount = iterMap->second.size();
135 schoenebeck 973 }
136     midiMapsMutex.Unlock();
137 iliev 981
138     if (InstrCount != -1) {
139     LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, Map, InstrCount));
140     }
141 schoenebeck 947 }
142    
143 schoenebeck 973 void MidiInstrumentMapper::RemoveAllEntries(int Map) {
144 iliev 981 int InstrCount = -1;
145    
146 schoenebeck 973 midiMapsMutex.Lock();
147     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
148     if (iterMap != midiMaps.end()) { // map found
149     iterMap->second.clear(); // clear that map
150 iliev 981 InstrCount = 0;
151 schoenebeck 973 }
152     midiMapsMutex.Unlock();
153 iliev 981
154     if (InstrCount != -1) {
155     LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, Map, InstrCount));
156     }
157 schoenebeck 947 }
158    
159 schoenebeck 973 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
160 schoenebeck 947 std::map<midi_prog_index_t,entry_t> result;
161 schoenebeck 973
162 schoenebeck 947 // copy the internal map first
163 schoenebeck 973 midiMapsMutex.Lock();
164     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
165     if (iterMap == midiMaps.end()) { // no such map
166     midiMapsMutex.Unlock();
167     throw Exception("There is no MIDI instrument map " + ToString(Map));
168     }
169     for (std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.begin();
170     iterEntry != iterMap->second.end(); iterEntry++)
171 schoenebeck 947 {
172     entry_t entry;
173 schoenebeck 973 entry.EngineName = iterEntry->second.EngineName;
174     entry.InstrumentFile = iterEntry->second.InstrumentFile;
175     entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
176     entry.Volume = iterEntry->second.Volume;
177     entry.Name = iterEntry->second.Name;
178     result[iterEntry->first] = entry;
179 schoenebeck 947 }
180 schoenebeck 973 midiMapsMutex.Unlock();
181    
182 schoenebeck 958 // complete it with current LoadMode of each entry
183 schoenebeck 947 for (std::map<midi_prog_index_t,entry_t>::iterator iter = result.begin();
184     iter != result.end(); iter++)
185     {
186     entry_t& entry = iter->second;
187     Engine* pEngine = EngineFactory::Create(entry.EngineName);
188     if (!pEngine) { // invalid mapping
189 schoenebeck 973 RemoveEntry(Map, iter->first);
190 schoenebeck 947 result.erase(iter);
191     continue;
192     }
193     InstrumentManager* pManager = pEngine->GetInstrumentManager();
194     if (pManager) { // engine provides an InstrumentManager
195     InstrumentManager::instrument_id_t id;
196     id.FileName = entry.InstrumentFile;
197     id.Index = entry.InstrumentIndex;
198     entry.LoadMode = static_cast<mode_t>(pManager->GetMode(id));
199     } else { // engine does not provide an InstrumentManager
200 schoenebeck 958 // use default value
201 schoenebeck 947 entry.LoadMode = ON_DEMAND;
202     }
203     EngineFactory::Destroy(pEngine);
204     }
205     return result;
206     }
207    
208 schoenebeck 973 std::vector<int> MidiInstrumentMapper::Maps() {
209     std::vector<int> result;
210     midiMapsMutex.Lock();
211     for (std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.begin();
212     iterMap != midiMaps.end(); iterMap++)
213     {
214     result.push_back(iterMap->first);
215     }
216     midiMapsMutex.Unlock();
217     return result;
218     }
219    
220     int MidiInstrumentMapper::AddMap(String MapName) throw (Exception) {
221     int ID;
222     midiMapsMutex.Lock();
223     if (midiMaps.empty()) ID = 0;
224     else {
225     // get the highest existing map ID
226     uint lastIndex = (--(midiMaps.end()))->first;
227     // check if we reached the index limit
228     if (lastIndex + 1 < lastIndex) {
229     // search for an unoccupied map ID starting from 0
230     for (uint i = 0; i < lastIndex; i++) {
231     if (midiMaps.find(i) != midiMaps.end()) continue;
232     // we found an unused ID, so insert the new map there
233     ID = i;
234     goto __create_map;
235     }
236     throw Exception("Internal error: could not find unoccupied MIDI instrument map ID.");
237     }
238 iliev 976 ID = lastIndex + 1;
239 schoenebeck 973 }
240     __create_map:
241     midiMaps[ID].name = MapName;
242     midiMapsMutex.Unlock();
243 iliev 981
244     LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
245 schoenebeck 973 return ID;
246     }
247    
248     String MidiInstrumentMapper::MapName(int Map) throw (Exception) {
249     String result;
250     midiMapsMutex.Lock();
251     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
252     if (iterMap == midiMaps.end()) {
253     midiMapsMutex.Unlock();
254     throw Exception("There is no MIDI instrument map " + ToString(Map));
255     }
256     result = iterMap->second.name;
257     midiMapsMutex.Unlock();
258     return result;
259     }
260    
261     void MidiInstrumentMapper::RenameMap(int Map, String NewName) throw (Exception) {
262     midiMapsMutex.Lock();
263     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
264     if (iterMap == midiMaps.end()) {
265     midiMapsMutex.Unlock();
266     throw Exception("There is no MIDI instrument map " + ToString(Map));
267     }
268     iterMap->second.name = NewName;
269     midiMapsMutex.Unlock();
270 iliev 981 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_info, Map));
271 schoenebeck 973 }
272    
273     void MidiInstrumentMapper::RemoveMap(int Map) {
274     midiMapsMutex.Lock();
275     midiMaps.erase(Map);
276     midiMapsMutex.Unlock();
277 iliev 981 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
278 schoenebeck 973 }
279    
280     void MidiInstrumentMapper::RemoveAllMaps() {
281     midiMapsMutex.Lock();
282     midiMaps.clear();
283     midiMapsMutex.Unlock();
284 iliev 981 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
285 schoenebeck 973 }
286    
287     optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
288 schoenebeck 947 optional<entry_t> result;
289 schoenebeck 973 midiMapsMutex.Lock();
290     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
291     if (iterMap != midiMaps.end()) { // map found
292     std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(Index);
293     if (iterEntry != iterMap->second.end()) {
294     entry_t entry;
295     entry.EngineName = iterEntry->second.EngineName;
296     entry.InstrumentFile = iterEntry->second.InstrumentFile;
297     entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
298     entry.Volume = iterEntry->second.Volume;
299     //TODO: for now we skip the LoadMode and Name entry here, since we don't need it in the MidiInputPort
300     result = entry;
301     }
302 schoenebeck 947 }
303 schoenebeck 973 midiMapsMutex.Unlock();
304 schoenebeck 947 return result;
305     }
306    
307     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC