1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: drummap.cpp,v 1.3.2.6 2009/10/29 02:14:37 terminator356 Exp $
5 //
6 //  (C) Copyright 1999/2000 Werner Schweer (ws@seh.de)
7 //  (C) Copyright 2016 Tim E. Real (terminator356 on users dot sourceforge dot net)
8 //
9 //  This program is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU General Public License
11 //  as published by the Free Software Foundation; version 2 of
12 //  the License, or (at your option) any later version.
13 //
14 //  This program is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 //  GNU General Public License for more details.
18 //
19 //  You should have received a copy of the GNU General Public License
20 //  along with this program; if not, write to the Free Software
21 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
22 //
23 //=========================================================
24 
25 #include "audio.h"
26 #include "drummap.h"
27 #include "xml.h"
28 #include "song.h"
29 
30 #include "helper.h"
31 
32 #include <QSet>
33 
34 namespace MusEGlobal {
35 char drumOutmap[DRUM_MAPSIZE];
36 char drumInmap[128];
37 MusECore::DrumMap drumMap[DRUM_MAPSIZE];
38 }
39 
40 namespace MusECore {
41 
42 //---------------------------------------------------------
43 //    GM default drum map
44 //---------------------------------------------------------
45 
46 // Default to track port if -1 and track channel if -1.  (These used to say 9, 0 for chan, port).
47 const DrumMap blankdm = { QString(""), 100, 16, 32, -1, -1, 70, 90, 110, 127, 127, 127, false, false };
48 
49 // this map should have 128 entries, as it's used for initialising iNewDrumMap as well.
50 // iNewDrumMap only has 128 entries. also, the every "out-note" ("anote") should be
51 // represented exactly once in idrumMap, and there shall be no duplicate or unused
52 // "out-notes".
53 // reason: iNewDrumMap is inited as follows: iterate through the full idrumMap[],
54 //         iNewDrumMap[ idrumMap[i].anote ] = idrumMap[i]
55 // if you ever want to change this, you will need to fix the initNewDrumMap() function.
56 const DrumMap idrumMap[DRUM_MAPSIZE] = {
57       { QString("Acoustic Bass Drum"), 100, 16, 32, -1, -1, 70, 90, 110, 127, 35, 35, false, false },
58       { QString("Bass Drum 1"),        100, 16, 32, -1, -1, 70, 90, 110, 127, 36, 36, false, false },
59       { QString("Side Stick"),         100, 16, 32, -1, -1, 70, 90, 110, 127, 37, 37, false, false },
60       { QString("Acoustic Snare"),     100, 16, 32, -1, -1, 70, 90, 110, 127, 38, 38, false, false },
61       { QString("Hand Clap"),          100, 16, 32, -1, -1, 70, 90, 110, 127, 39, 39, false, false },
62       { QString("Electric Snare"),     100, 16, 32, -1, -1, 70, 90, 110, 127, 40, 40, false, false },
63       { QString("Low Floor Tom"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 41, 41, false, false },
64       { QString("Closed Hi-Hat"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 42, 42, false, false },
65       { QString("High Floor Tom"),     100, 16, 32, -1, -1, 70, 90, 110, 127, 43, 43, false, false },
66       { QString("Pedal Hi-Hat"),       100, 16, 32, -1, -1, 70, 90, 110, 127, 44, 44, false, false },
67       { QString("Low Tom"),            100, 16, 32, -1, -1, 70, 90, 110, 127, 45, 45, false, false },
68       { QString("Open Hi-Hat"),        100, 16, 32, -1, -1, 70, 90, 110, 127, 46, 46, false, false },
69       { QString("Low-Mid Tom"),        100, 16, 32, -1, -1, 70, 90, 110, 127, 47, 47, false, false },
70       { QString("Hi-Mid Tom"),         100, 16, 32, -1, -1, 70, 90, 110, 127, 48, 48, false, false },
71       { QString("Crash Cymbal 1"),     100, 16, 32, -1, -1, 70, 90, 110, 127, 49, 49, false, false },
72       { QString("High Tom"),           100, 16, 32, -1, -1, 70, 90, 110, 127, 50, 50, false, false },
73 
74       { QString("Ride Cymbal 1"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 51, 51, false, false },
75       { QString("Chinese Cymbal"),     100, 16, 32, -1, -1, 70, 90, 110, 127, 52, 52, false, false },
76       { QString("Ride Bell"),          100, 16, 32, -1, -1, 70, 90, 110, 127, 53, 53, false, false },
77       { QString("Tambourine"),         100, 16, 32, -1, -1, 70, 90, 110, 127, 54, 54, false, false },
78       { QString("Splash Cymbal"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 55, 55, false, false },
79       { QString("Cowbell"),            100, 16, 32, -1, -1, 70, 90, 110, 127, 56, 56, false, false },
80       { QString("Crash Cymbal 2"),     100, 16, 32, -1, -1, 70, 90, 110, 127, 57, 57, false, false },
81       { QString("Vibraslap"),          100, 16, 32, -1, -1, 70, 90, 110, 127, 58, 58, false, false },
82       { QString("Ride Cymbal 2"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 59, 59, false, false },
83       { QString("Hi Bongo"),           100, 16, 32, -1, -1, 70, 90, 110, 127, 60, 60, false, false },
84       { QString("Low Bongo"),          100, 16, 32, -1, -1, 70, 90, 110, 127, 61, 61, false, false },
85       { QString("Mute Hi Conga"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 62, 62, false, false },
86       { QString("Open Hi Conga"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 63, 63, false, false },
87       { QString("Low Conga"),          100, 16, 32, -1, -1, 70, 90, 110, 127, 64, 64, false, false },
88       { QString("High Timbale"),       100, 16, 32, -1, -1, 70, 90, 110, 127, 65, 65, false, false },
89       { QString("Low Timbale"),        100, 16, 32, -1, -1, 70, 90, 110, 127, 66, 66, false, false },
90 
91       { QString("High Agogo"),         100, 16, 32, -1, -1, 70, 90, 110, 127, 67, 67, false, false },
92       { QString("Low Agogo"),          100, 16, 32, -1, -1, 70, 90, 110, 127, 68, 68, false, false },
93       { QString("Cabasa"),             100, 16, 32, -1, -1, 70, 90, 110, 127, 69, 69, false, false },
94       { QString("Maracas"),            100, 16, 32, -1, -1, 70, 90, 110, 127, 70, 70, false, false },
95       { QString("Short Whistle"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 71, 71, false, false },
96       { QString("Long Whistle"),       100, 16, 32, -1, -1, 70, 90, 110, 127, 72, 72, false, false },
97       { QString("Short Guiro"),        100, 16, 32, -1, -1, 70, 90, 110, 127, 73, 73, false, false },
98       { QString("Long Guiro"),         100, 16, 32, -1, -1, 70, 90, 110, 127, 74, 74, false, false },
99       { QString("Claves"),             100, 16, 32, -1, -1, 70, 90, 110, 127, 75, 75, false, false },
100       { QString("Hi Wood Block"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 76, 76, false, false },
101       { QString("Low Wood Block"),     100, 16, 32, -1, -1, 70, 90, 110, 127, 77, 77, false, false },
102       { QString("Mute Cuica"),         100, 16, 32, -1, -1, 70, 90, 110, 127, 78, 78, false, false },
103       { QString("Open Cuica"),         100, 16, 32, -1, -1, 70, 90, 110, 127, 79, 79, false, false },
104       { QString("Mute Triangle"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 80, 80, false, false },
105       { QString("Open Triangle"),      100, 16, 32, -1, -1, 70, 90, 110, 127, 81, 81, false, false },
106       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 82, 82, false, false },
107 
108       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 83, 83, false, false },
109       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 84, 84, false, false },
110       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 85, 85, false, false },
111       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 86, 86, false, false },
112       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 87, 87, false, false },
113       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 88, 88, false, false },
114       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 89, 89, false, false },
115       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 90, 90, false, false },
116       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 91, 91, false, false },
117       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 92, 92, false, false },
118       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 93, 93, false, false },
119       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 94, 94, false, false },
120       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 95, 95, false, false },
121       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 96, 96, false, false },
122       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 97, 97, false, false },
123       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 98, 98, false, false },
124 
125       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 99, 99, false, false },
126       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 100, 100, false, false },
127       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 101, 101, false, false },
128       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 102, 102, false, false },
129       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 103, 103, false, false },
130       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 104, 104, false, false },
131       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 105, 105, false, false },
132       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 106, 106, false, false },
133       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 107, 107, false, false },
134       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 108, 108, false, false },
135       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 109, 109, false, false },
136       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 110, 110, false, false },
137       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 111, 111, false, false },
138       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 112, 112, false, false },
139       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 113, 113, false, false },
140       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 114, 114, false, false },
141 
142       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 115, 115, false, false },
143       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 116, 116, false, false },
144       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 117, 117, false, false },
145       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 118, 118, false, false },
146       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 119, 119, false, false },
147       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 120, 120, false, false },
148       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 121, 121, false, false },
149       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 122, 122, false, false },
150       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 123, 123, false, false },
151       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 124, 124, false, false },
152       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 125, 125, false, false },
153       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 126, 126, false, false },
154       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 127, 127, false, false },
155       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 0, 0, false, false },
156       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 1, 1, false, false },
157       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 2, 2, false, false },
158 
159       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 3, 3, false, false },
160       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 4, 4, false, false },
161       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 5, 5, false, false },
162       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 6, 6, false, false },
163       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 7, 7, false, false },
164       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 8, 8, false, false },
165       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 9, 9, false, false },
166       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 10, 10, false, false },
167       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 11, 11, false, false },
168       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 12, 12, false, false },
169       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 13, 13, false, false },
170       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 14, 14, false, false },
171       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 15, 15, false, false },
172       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 16, 16, false, false },
173       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 17, 17, false, false },
174       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 18, 18, false, false },
175 
176       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 19, 19, false, false },
177       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 20, 20, false, false },
178       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 21, 21, false, false },
179       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 22, 22, false, false },
180       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 23, 23, false, false },
181       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 24, 24, false, false },
182       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 25, 25, false, false },
183       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 26, 26, false, false },
184       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 27, 27, false, false },
185       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 28, 28, false, false },
186       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 29, 29, false, false },
187       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 30, 30, false, false },
188       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 31, 31, false, false },
189       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 32, 32, false, false },
190       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 33, 33, false, false },
191       { QString(""),                   100, 16, 32, -1, -1, 70, 90, 110, 127, 34, 34, false, false }
192       };
193 
194 DrumMap iNewDrumMap[128];
195 
initNewDrumMap()196 void initNewDrumMap()
197 {
198   bool done[128];
199   for (int i=0;i<128;i++) done[i]=false;
200 
201   for (int i=0;i<DRUM_MAPSIZE;i++)
202   {
203     int idx=idrumMap[i].anote;
204     if (idx < 0 || idx >= 128)
205       fprintf(stderr, "ERROR: THIS SHOULD NEVER HAPPEN: idrumMap[%i].anote is not within 0..127!\n", idx);
206     else
207     {
208       if (done[idx]==true)
209       {
210         fprintf(stderr, "ERROR: iNewDrumMap[%i] is already initialized!\n"
211                "       this will be probably not a problem, but some programmer didn't read\n"
212                "       flo's comment at drummap.cpp, above idrumMap[].\n", idx);
213       }
214       else
215       {
216         iNewDrumMap[idx]=idrumMap[i];
217         done[idx]=true;
218       }
219     }
220   }
221 
222   for (int i=0;i<128;i++)
223   {
224     if (done[i]==false)
225     {
226       fprintf(stderr, "ERROR: iNewDrumMap[%i] is uninitialized!\n"
227              "       this will be probably not a problem, but some programmer didn't read\n"
228              "       flo's comment at drummap.cpp, above idrumMap[].\n", i);
229       iNewDrumMap[i].name="";
230       iNewDrumMap[i].vol=100;
231       iNewDrumMap[i].quant=16;
232       iNewDrumMap[i].len=32;
233       iNewDrumMap[i].lv1=70;
234       iNewDrumMap[i].lv2=90;
235       iNewDrumMap[i].lv3=127;
236       iNewDrumMap[i].lv4=110;
237       iNewDrumMap[i].enote=i;
238       iNewDrumMap[i].anote=i;
239       iNewDrumMap[i].mute=false;
240       iNewDrumMap[i].hide=false;
241     }
242   }
243 }
244 
245 //---------------------------------------------------------
246 //   clearDrumMap
247 //    One-time only early init
248 //---------------------------------------------------------
249 
clearDrumMap()250 void clearDrumMap()
251       {
252       for (int i = 0; i < DRUM_MAPSIZE; ++i) {
253             DrumMap& d = MusEGlobal::drumMap[i];
254             d.vol = d.len = d.channel = d.port = d.lv1 = d.lv2 = d.lv3 = d.lv4 = d.enote = d.anote = 0;
255             d.mute = d.hide = false;
256          }
257       }
258 //---------------------------------------------------------
259 //   initDrumMap
260 //    populate Inmap and Outmap
261 //---------------------------------------------------------
262 
initDrumMap()263 void initDrumMap()
264       {
265       for (int i = 0; i < DRUM_MAPSIZE; ++i) {
266             DrumMap& d = MusEGlobal::drumMap[i];
267             //Make sure we're not overwriting any values loaded
268             //On init, all these values are zero. If so, just set the drummap entry to the initial drummap entry.
269             if (!(d.vol || d.len || d.channel || d.port || d.lv1 || d.lv2 || d.lv3 || d.lv4 || d.enote || d.anote || d.mute || d.hide))
270                   MusEGlobal::drumMap[i] = idrumMap[i];
271          }
272       //Finally, setup the inMap, outMap-values
273       memset(MusEGlobal::drumInmap, 0, sizeof(MusEGlobal::drumInmap));
274       memset(MusEGlobal::drumOutmap, 0, sizeof(MusEGlobal::drumOutmap));
275       for (int i = 0; i < DRUM_MAPSIZE; ++i) {
276             MusEGlobal::drumInmap[(unsigned int)(MusEGlobal::drumMap[i].enote)] = i;
277             MusEGlobal::drumOutmap[(unsigned int)(MusEGlobal::drumMap[i].anote)] = i;
278             }
279       }
280 
281 //---------------------------------------------------------
282 //   resetGMDrumMap
283 //---------------------------------------------------------
284 
resetGMDrumMap()285 void resetGMDrumMap()
286       {
287       for(int i = 0; i < DRUM_MAPSIZE; ++i)
288         MusEGlobal::drumMap[i] = idrumMap[i];
289       memset(MusEGlobal::drumInmap, 0, sizeof(MusEGlobal::drumInmap));
290       memset(MusEGlobal::drumOutmap, 0, sizeof(MusEGlobal::drumOutmap));
291       for (int i = 0; i < DRUM_MAPSIZE; ++i) {
292             MusEGlobal::drumInmap[(unsigned int)(MusEGlobal::drumMap[i].enote)] = i;
293             MusEGlobal::drumOutmap[(unsigned int)(MusEGlobal::drumMap[i].anote)] = i;
294             }
295       }
296 
297 //---------------------------------------------------------
298 //   operator ==
299 //---------------------------------------------------------
300 
operator ==(const DrumMap & map) const301 bool DrumMap::operator==(const DrumMap& map) const
302       {
303         // Everything equal, including mute and hide settings?
304         return almost_equals(map) &&
305                mute == map.mute &&
306                hide == map.hide;
307       }
308 
almost_equals(const DrumMap & map) const309 bool DrumMap::almost_equals(const DrumMap& map) const
310 {
311       // Disregarding mute and hide settings.
312       return
313          name == map.name
314          && vol == map.vol
315          && quant == map.quant
316          && len == map.len
317          && channel == map.channel
318          && port == map.port
319          && lv1 == map.lv1
320          && lv2 == map.lv2
321          && lv3 == map.lv3
322          && lv4 == map.lv4
323          && enote == map.enote
324          && anote == map.anote;
325 }
326 
dump()327 void DrumMap::dump()
328 {
329   fprintf(stderr, "%s\t\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d(%s)\t\t%d(%s)\t\t%d\t%d\t\n",
330       name.toLatin1().constData(),
331       vol,
332       quant,
333       len,
334       channel,
335       port,
336       lv1, lv2, lv3, lv4,
337       enote, pitch2string(enote).toLatin1().constData(),
338       anote, pitch2string(anote).toLatin1().constData(),
339       mute,
340       hide);
341 }
342 
343 //---------------------------------------------------------
344 //   writeDrumMap
345 //---------------------------------------------------------
346 
writeDrumMap(int level,Xml & xml,bool external)347 void writeDrumMap(int level, Xml& xml, bool external)
348       {
349       xml.tag(level++, "drummap");
350       for (int i = 0; i < DRUM_MAPSIZE; ++i) {
351             DrumMap* dm = &MusEGlobal::drumMap[i];
352             const DrumMap* idm = &idrumMap[i];
353 
354             if (external) {
355                   xml.tag(level++, "entry");
356                   xml.strTag(level, "name", dm->name);
357                   xml.intTag(level, "vol", dm->vol);
358                   xml.intTag(level, "quant", dm->quant);
359                   xml.intTag(level, "len", dm->len);
360                   xml.intTag(level, "channel", dm->channel);
361                   xml.intTag(level, "port", dm->port);
362                   xml.intTag(level, "lv1", dm->lv1);
363                   xml.intTag(level, "lv2", dm->lv2);
364                   xml.intTag(level, "lv3", dm->lv3);
365                   xml.intTag(level, "lv4", dm->lv4);
366                   xml.intTag(level, "enote", dm->enote);
367                   xml.intTag(level, "anote", dm->anote);
368                   xml.intTag(level, "hide", dm->hide);
369                   }
370             else {
371                   // write only, if entry is different from initial entry
372                   if (!external && *dm == *idm)
373                         continue;
374                   xml.tag(level++, "entry idx=\"%d\"", i);
375                   if (dm->name != idm->name)
376                         xml.strTag(level, "name", dm->name);
377                   if (dm->vol != idm->vol)
378                         xml.intTag(level, "vol", dm->vol);
379                   if (dm->quant != idm->quant)
380                         xml.intTag(level, "quant", dm->quant);
381                   if (dm->len != idm->len)
382                         xml.intTag(level, "len", dm->len);
383                   if (dm->channel != idm->channel)
384                         xml.intTag(level, "channel", dm->channel);
385                   if (dm->port != idm->port)
386                         xml.intTag(level, "port", dm->port);
387                   if (dm->lv1 != idm->lv1)
388                         xml.intTag(level, "lv1", dm->lv1);
389                   if (dm->lv2 != idm->lv2)
390                         xml.intTag(level, "lv2", dm->lv2);
391                   if (dm->lv3 != idm->lv3)
392                         xml.intTag(level, "lv3", dm->lv3);
393                   if (dm->lv4 != idm->lv4)
394                         xml.intTag(level, "lv4", dm->lv4);
395                   if (dm->enote != idm->enote)
396                         xml.intTag(level, "enote", dm->enote);
397                   if (dm->anote != idm->anote)
398                         xml.intTag(level, "anote", dm->anote);
399                   if (dm->mute != idm->mute)
400                         xml.intTag(level, "mute", dm->mute);
401                   if (dm->hide != idm->hide)
402                         xml.intTag(level, "hide", dm->hide);
403                   }
404             xml.tag(level--, "/entry");
405             }
406       xml.tag(level--, "/drummap");
407       }
408 
409 //---------------------------------------------------------
410 //   readDrummapEntry
411 //---------------------------------------------------------
412 
readDrummapEntry(Xml & xml,DrumMap * dm)413 static void readDrummapEntry(Xml& xml, DrumMap* dm)
414       {
415 
416       for (;;) {
417             Xml::Token token = xml.parse();
418             const QString& tag = xml.s1();
419             switch (token) {
420                   case Xml::Error:
421                   case Xml::End:
422                         return;
423                   case Xml::TagStart:
424                         if (tag == "name")
425                               dm->name = xml.parse(QString("name"));
426                         else if (tag == "vol")
427                               dm->vol = (unsigned char)xml.parseInt();
428                         else if (tag == "quant")
429                               dm->quant = xml.parseInt();
430                         else if (tag == "len")
431                               dm->len = xml.parseInt();
432                         else if (tag == "channel")
433                               dm->channel = xml.parseInt();
434                         else if (tag == "port")
435                               dm->port = xml.parseInt();
436                         else if (tag == "lv1")
437                               dm->lv1 = xml.parseInt();
438                         else if (tag == "lv2")
439                               dm->lv2 = xml.parseInt();
440                         else if (tag == "lv3")
441                               dm->lv3 = xml.parseInt();
442                         else if (tag == "lv4")
443                               dm->lv4 = xml.parseInt();
444                         else if (tag == "enote")
445                               dm->enote = xml.parseInt();
446                         else if (tag == "anote")
447                               dm->anote = xml.parseInt();
448                         else if (tag == "mute")
449                               dm->mute = xml.parseInt();
450                         else if (tag == "hide")
451                               dm->hide = xml.parseInt();
452                         else if (tag == "selected")
453                               //; // dm->selected = xml.parseInt();
454                               xml.skip(tag);
455                         else
456                               xml.unknown("entry");
457                         break;
458                   case Xml::Attribut:
459                         if (tag == "idx") {
460                               int idx = xml.s2().toInt() & 0x7f;
461                               dm = &MusEGlobal::drumMap[idx];
462 
463                               }
464                         break;
465                   case Xml::TagEnd:
466                         if (tag == "entry")
467                         {
468                               return;
469                         }
470                   default:
471                         break;
472                   }
473             }
474       }
475 
476 //---------------------------------------------------------
477 //   readDrummap
478 //---------------------------------------------------------
479 
readDrumMap(Xml & xml,bool external)480 void readDrumMap(Xml& xml, bool external)
481       {
482       if (external) {
483             for (int i = 0; i < DRUM_MAPSIZE; ++i)
484                   MusEGlobal::drumMap[i] = blankdm;
485             }
486       else {
487             for (int i = 0; i < DRUM_MAPSIZE; ++i)
488                   MusEGlobal::drumMap[i] = idrumMap[i];
489             }
490       int i = 0;
491       for (;;) {
492             Xml::Token token = xml.parse();
493             const QString& tag = xml.s1();
494             switch (token) {
495                   case Xml::Error:
496                   case Xml::End:
497 //                             goto read_drummap_end;
498                             return;
499                   case Xml::TagStart:
500                         if (tag == "entry") {
501                               if(i >= DRUM_MAPSIZE)
502 //                                 goto read_drummap_end;
503                                 return;
504                               readDrummapEntry(xml, external ? &MusEGlobal::drumMap[i] : 0);
505                               ++i;
506                               }
507                         else if (tag == "comment")
508                               xml.parse();
509                         else
510                               xml.unknown("DrumMap");
511                         break;
512                   case Xml::Attribut:
513                         break;
514                   case Xml::TagEnd:
515                         if (tag == "drummap") {
516                               memset(MusEGlobal::drumInmap, 0, sizeof(MusEGlobal::drumInmap));
517                               memset(MusEGlobal::drumOutmap, 0, sizeof(MusEGlobal::drumOutmap));
518                               for (int i = 0; i < DRUM_MAPSIZE; ++i) {
519                                     MusEGlobal::drumInmap[(unsigned int)(MusEGlobal::drumMap[i].enote)] = i;
520                                     MusEGlobal::drumOutmap[(unsigned int)(MusEGlobal::drumMap[i].anote)] = i;
521                                     }
522 //                               goto read_drummap_end;
523                               return;
524                               }
525                   default:
526                         break;
527                   }
528             }
529       }
530 
531 } // namespace MusECore
532 
533