/[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 981 - (show annotations) (download)
Sun Dec 17 22:35:01 2006 UTC (17 years, 4 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 /***************************************************************************
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 #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 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 privateEntry.Volume = Entry.Volume;
100 privateEntry.Name = Entry.Name;
101
102 bool Replaced = false;
103 int InstrCount = 0;
104
105 midiMapsMutex.Lock();
106 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
107 if (iterMap != midiMaps.end()) { // map found
108 Replaced = (iterMap->second.find(Index) != iterMap->second.end());
109 iterMap->second[Index] = privateEntry;
110 InstrCount = iterMap->second.size();
111 } 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 EngineFactory::Destroy(pEngine);
118
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 }
126
127 void MidiInstrumentMapper::RemoveEntry(int Map, midi_prog_index_t Index) {
128 int InstrCount = -1;
129
130 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 InstrCount = iterMap->second.size();
135 }
136 midiMapsMutex.Unlock();
137
138 if (InstrCount != -1) {
139 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, Map, InstrCount));
140 }
141 }
142
143 void MidiInstrumentMapper::RemoveAllEntries(int Map) {
144 int InstrCount = -1;
145
146 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 InstrCount = 0;
151 }
152 midiMapsMutex.Unlock();
153
154 if (InstrCount != -1) {
155 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_count, Map, InstrCount));
156 }
157 }
158
159 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
160 std::map<midi_prog_index_t,entry_t> result;
161
162 // copy the internal map first
163 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 {
172 entry_t entry;
173 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 }
180 midiMapsMutex.Unlock();
181
182 // complete it with current LoadMode of each entry
183 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 RemoveEntry(Map, iter->first);
190 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 // use default value
201 entry.LoadMode = ON_DEMAND;
202 }
203 EngineFactory::Destroy(pEngine);
204 }
205 return result;
206 }
207
208 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 ID = lastIndex + 1;
239 }
240 __create_map:
241 midiMaps[ID].name = MapName;
242 midiMapsMutex.Unlock();
243
244 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
245 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 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_info, Map));
271 }
272
273 void MidiInstrumentMapper::RemoveMap(int Map) {
274 midiMapsMutex.Lock();
275 midiMaps.erase(Map);
276 midiMapsMutex.Unlock();
277 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
278 }
279
280 void MidiInstrumentMapper::RemoveAllMaps() {
281 midiMapsMutex.Lock();
282 midiMaps.clear();
283 midiMapsMutex.Unlock();
284 LSCPServer::SendLSCPNotify(LSCPEvent(LSCPEvent::event_midi_instr_map_count, Maps().size()));
285 }
286
287 optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
288 optional<entry_t> result;
289 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 }
303 midiMapsMutex.Unlock();
304 return result;
305 }
306
307 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC