/[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 973 - (show annotations) (download)
Fri Dec 15 21:40:27 2006 UTC (17 years, 4 months ago) by schoenebeck
File size: 11872 byte(s)
* revised and extended MIDI instrument mapping feature to allow managing
  arbitrary amount of maps and assigning each sampler channel individually
  to one map (this commit batch includes LSCP spec document update and
  respective implementation on LS side)

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

  ViewVC Help
Powered by ViewVC