/[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 1040 - (hide annotations) (download)
Wed Feb 7 15:41:31 2007 UTC (17 years, 2 months ago) by schoenebeck
File size: 13411 byte(s)
* bugfix: sampler crashed when trying to persistently map a not existent or
  corrupt .gig file ("MAP MIDI_INSTRUMENT ... PERSISTENT")
* behavior fix: reset FX send levels i.e. when receiving a MIDI "reset all
  controllers" message
* bumped version to 0.4.0.3cvs

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

  ViewVC Help
Powered by ViewVC