/[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 1040 - (show annotations) (download)
Wed Feb 7 15:41:31 2007 UTC (17 years, 1 month 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 /***************************************************************************
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 #include "../../network/lscpserver.h"
27
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 float Volume;
36 String Name;
37 };
38
39 // 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
45 // here we store all maps
46 std::map<int,MidiInstrumentMap> midiMaps;
47
48 // for synchronization of midiMaps
49 Mutex midiMapsMutex;
50
51
52 void MidiInstrumentMapper::AddOrReplaceEntry(int Map, midi_prog_index_t Index, entry_t Entry, bool bInBackground) throw (Exception) {
53 if (bInBackground) {
54 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d in background\n",
55 Map,
56 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 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d\n",
62 Map,
63 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 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 if (!Entry.InstrumentFile.size())
75 throw Exception("No instrument file name given");
76 // TODO: an easy one - we should check here if given file exists and throw an exception if it doesn't
77 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 privateEntry.Volume = Entry.Volume;
101 privateEntry.Name = Entry.Name;
102
103 bool Replaced = false;
104 int InstrCount = 0;
105
106 midiMapsMutex.Lock();
107 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
108 if (iterMap != midiMaps.end()) { // map found
109 Replaced = (iterMap->second.find(Index) != iterMap->second.end());
110 iterMap->second[Index] = privateEntry;
111 InstrCount = iterMap->second.size();
112 } 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 EngineFactory::Destroy(pEngine);
119
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 }
127
128 void MidiInstrumentMapper::RemoveEntry(int Map, midi_prog_index_t Index) {
129 int InstrCount = -1;
130
131 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 InstrCount = iterMap->second.size();
136 }
137 midiMapsMutex.Unlock();
138
139 if (InstrCount != -1) {
140 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, Map, InstrCount));
141 }
142 }
143
144 void MidiInstrumentMapper::RemoveAllEntries(int Map) {
145 int InstrCount = -1;
146
147 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 InstrCount = 0;
152 }
153 midiMapsMutex.Unlock();
154
155 if (InstrCount != -1) {
156 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, Map, InstrCount));
157 }
158 }
159
160 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
161 std::map<midi_prog_index_t,entry_t> result;
162
163 // copy the internal map first
164 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 {
173 entry_t entry;
174 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 }
181 midiMapsMutex.Unlock();
182
183 // complete it with current LoadMode of each entry
184 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 RemoveEntry(Map, iter->first);
191 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 // use default value
202 entry.LoadMode = ON_DEMAND;
203 }
204 EngineFactory::Destroy(pEngine);
205 }
206 return result;
207 }
208
209 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 ID = lastIndex + 1;
240 }
241 __create_map:
242 midiMaps[ID].name = MapName;
243 midiMapsMutex.Unlock();
244
245 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
246 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 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_info, Map));
272 }
273
274 void MidiInstrumentMapper::RemoveMap(int Map) {
275 midiMapsMutex.Lock();
276 midiMaps.erase(Map);
277 midiMapsMutex.Unlock();
278 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
279 }
280
281 void MidiInstrumentMapper::RemoveAllMaps() {
282 midiMapsMutex.Lock();
283 midiMaps.clear();
284 midiMapsMutex.Unlock();
285 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
286 }
287
288 optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
289 optional<entry_t> result;
290 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 }
304 midiMapsMutex.Unlock();
305 return result;
306 }
307
308 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC