/[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 973 - (hide 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 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    
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 schoenebeck 958 float Volume;
35 schoenebeck 947 String Name;
36     };
37    
38 schoenebeck 973 // 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 schoenebeck 947
44 schoenebeck 973 // here we store all maps
45     std::map<int,MidiInstrumentMap> midiMaps;
46 schoenebeck 947
47 schoenebeck 973 // for synchronization of midiMaps
48     Mutex midiMapsMutex;
49 schoenebeck 947
50 schoenebeck 973
51     void MidiInstrumentMapper::AddOrReplaceEntry(int Map, midi_prog_index_t Index, entry_t Entry, bool bInBackground) throw (Exception) {
52 schoenebeck 947 if (bInBackground) {
53 schoenebeck 973 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d in background\n",
54     Map,
55 schoenebeck 947 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 schoenebeck 973 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d\n",
61     Map,
62 schoenebeck 947 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 schoenebeck 973 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 schoenebeck 970 if (!Entry.InstrumentFile.size())
74     throw Exception("No instrument file name given");
75 schoenebeck 947 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 schoenebeck 958 privateEntry.Volume = Entry.Volume;
99 schoenebeck 947 privateEntry.Name = Entry.Name;
100 schoenebeck 973 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 schoenebeck 947 EngineFactory::Destroy(pEngine);
111     }
112    
113 schoenebeck 973 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 schoenebeck 947 }
121    
122 schoenebeck 973 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 schoenebeck 947 }
130    
131 schoenebeck 973 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
132 schoenebeck 947 std::map<midi_prog_index_t,entry_t> result;
133 schoenebeck 973
134 schoenebeck 947 // copy the internal map first
135 schoenebeck 973 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 schoenebeck 947 {
144     entry_t entry;
145 schoenebeck 973 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 schoenebeck 947 }
152 schoenebeck 973 midiMapsMutex.Unlock();
153    
154 schoenebeck 958 // complete it with current LoadMode of each entry
155 schoenebeck 947 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 schoenebeck 973 RemoveEntry(Map, iter->first);
162 schoenebeck 947 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 schoenebeck 958 // use default value
173 schoenebeck 947 entry.LoadMode = ON_DEMAND;
174     }
175     EngineFactory::Destroy(pEngine);
176     }
177     return result;
178     }
179    
180 schoenebeck 973 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 schoenebeck 947 optional<entry_t> result;
256 schoenebeck 973 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 schoenebeck 947 }
270 schoenebeck 973 midiMapsMutex.Unlock();
271 schoenebeck 947 return result;
272     }
273    
274     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC