/[svn]/linuxsampler/trunk/src/engines/sfz/LookupTable.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/sfz/LookupTable.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3593 - (show annotations) (download)
Mon Sep 2 16:53:16 2019 UTC (4 months, 3 weeks ago) by persson
File size: 13164 byte(s)
* SFZ format engine: fixed support for regions with loccN/hiccN
  conditions on more than one MIDI controller.

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2010 - 2019 Andreas Persson *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, *
20 * MA 02110-1301 USA *
21 ***************************************************************************/
22
23 #include "LookupTable.h"
24 #include <cstdio>
25 #include <set>
26 #include "../../common/global_private.h"
27
28 namespace sfz {
29
30 struct LookupTable::DimDef {
31 const int Definition::* lo;
32 const int Definition::* hi;
33 const uint8_t Query::* qarg;
34 int min;
35 int max;
36 const char* str;
37 };
38
39 // List of all dimensions handled by the lookup table, except
40 // control change. Only uint8_t types are currently supported.
41 const LookupTable::DimDef LookupTable::dimDefs[] = {
42 { &Region::lochan, &Region::hichan,
43 &Query::chan, 1, 16, "chan" },
44 { &Region::lokey, &Region::hikey,
45 &Query::key, 0, 127, "key" },
46 { &Region::lovel, &Region::hivel,
47 &Query::vel, 0, 127, "vel" },
48 { &Region::lochanaft, &Region::hichanaft,
49 &Query::chanaft, 0, 127, "chanaft" },
50 { &Region::lopolyaft, &Region::hipolyaft,
51 &Query::polyaft, 0, 127, "polyaft" },
52 { &Region::loprog, &Region::hiprog,
53 &Query::prog, 0, 127, "prog" },
54 { &Region::sw_previous, &Region::sw_previous,
55 &Query::prev_sw_key, -1, -1, "sw_previous" },
56 { 0, 0, 0, 0 }
57 };
58
59 // fills a mapping array for a given dimension
60 int LookupTable::fillMapArr(const std::vector<Region*>& regions,
61 const int Definition::* lo,
62 const int Definition::* hi,
63 int min, int max, int* a) {
64 std::set<int> s;
65 s.insert(min);
66 s.insert(max + 1);
67 for (std::vector<Region*>::const_iterator i = regions.begin() ;
68 i != regions.end() ; ++i) {
69 s.insert((*i)->*lo);
70 s.insert((*i)->*hi + 1);
71 }
72
73 int j = min;
74 int l = -1;
75 for (std::set<int>::const_iterator i = s.begin() ;
76 i != s.end() ; ++i) {
77 dmsg(2,(" %d", *i));
78 for ( ; j < *i ; j++) {
79 a[j] = l;
80 }
81 l++;
82 }
83 dmsg(2,("\n"));
84 return l;
85 }
86
87 // fills a mapping array for a given control change number
88 int LookupTable::fillMapArr(const std::vector<Region*>& regions,
89 int cc, int* a, int triggercc) {
90 std::set<int> s;
91 s.insert(0);
92 s.insert(128);
93 for (std::vector<Region*>::const_iterator i = regions.begin() ;
94 i != regions.end() ; ++i) {
95 int lo = (*i)->locc[cc];
96 int hi = (*i)->hicc[cc];
97 if (cc == triggercc) {
98 lo = std::max(lo, (*i)->on_locc[cc]);
99 hi = std::min(hi, (*i)->on_hicc[cc]);
100 }
101
102 s.insert(lo);
103 s.insert(hi + 1);
104 }
105
106 int j = 0;
107 int l = -1;
108 for (std::set<int>::const_iterator i = s.begin() ;
109 i != s.end() ; ++i) {
110 dmsg(2,(" %d", *i));
111 for ( ; j < *i ; j++) {
112 a[j] = l;
113 }
114 l++;
115 }
116 dmsg(2,("\n"));
117 return l;
118 }
119
120 LinuxSampler::ArrayList<Region*>&
121 LookupTable::query(const Query& q) const {
122 int offset = 0;
123 int dim;
124 for (dim = 0 ; qargs[dim] ; dim++) {
125 offset += mapArr[dim][int8_t(q.*qargs[dim])];
126 }
127 for (int cc = 0 ; ccargs[cc] >= 0 ; cc++, dim++) {
128 offset += mapArr[dim][q.cc[ccargs[cc]]];
129 }
130 return regionArr[offset];
131 }
132
133 // recursively fills the region array with regions
134 void LookupTable::fillRegionArr(const int* len, Region* region,
135 std::vector<int>::size_type dim, int j,
136 int triggercc) {
137 if (dim == dims.size() + ccs.size()) {
138 regionArr[j].add(region);
139 } else if (dim < dims.size()) {
140 int d = dims[dim];
141 int hi = region->*dimDefs[d].hi;
142 // special case for sw_previous
143 if (hi == -1) hi = 127;
144 for (int l = mapArr[dim][region->*dimDefs[d].lo] ;
145 l <= mapArr[dim][hi] ; l++) {
146 fillRegionArr(len, region, dim + 1, j * len[dim] + l,
147 triggercc);
148 }
149 } else {
150 int cc = ccs[dim - dims.size()];
151 int lo = region->locc[cc];
152 int hi = region->hicc[cc];
153 if (cc == triggercc) {
154 lo = std::max(lo, region->on_locc[cc]);
155 hi = std::min(hi, region->on_hicc[cc]);
156 }
157 for (int l = mapArr[dim][lo] ; l <= mapArr[dim][hi] ; l++) {
158 fillRegionArr(len, region, dim + 1, j * len[dim] + l,
159 triggercc);
160 }
161 }
162 }
163
164
165 LookupTable::LookupTable(const Instrument* instrument, int triggercc) {
166 std::vector<Region*> regions;
167
168 // copy the interesting regions
169 for (std::vector<Region*>::const_iterator i =
170 instrument->regions.begin() ;
171 i != instrument->regions.end() ; ++i) {
172
173 if (triggercc == -1) {
174 if ((*i)->lokey >= 0) {
175 regions.push_back(*i);
176 }
177 } else {
178 if ((*i)->hikey < 0 &&
179 (*i)->on_locc[triggercc] >= 0 &&
180 (*i)->on_hicc[triggercc] >= 0) {
181 regions.push_back(*i);
182 }
183 }
184 }
185
186 dmsg(2,("\nregions before filter: %d, after: %d\n",
187 int(instrument->regions.size()), int(regions.size())));
188
189 // find dimensions used by the instrument
190 for (int dim = 0 ; dimDefs[dim].lo ; dim++) {
191 for (std::vector<Region*>::const_iterator i = regions.begin() ;
192 i != regions.end() ; ++i) {
193
194 if ((triggercc == -1 || dimDefs[dim].lo != &Region::lokey) &&
195 ((*i)->*dimDefs[dim].lo != dimDefs[dim].min ||
196 (*i)->*dimDefs[dim].hi != dimDefs[dim].max)) {
197 dims.push_back(dim);
198 break;
199 }
200 }
201 }
202
203 // create and fill the qargs array with pointers to Query
204 // members
205 qargs = new const uint8_t Query::*[dims.size() + 1];
206 for (std::vector<int>::size_type i = 0 ; i < dims.size() ; i++) {
207 dmsg(2,("qargs %d: %s\n", int(i), dimDefs[dims[i]].str));
208 qargs[i] = dimDefs[dims[i]].qarg;
209 }
210 qargs[dims.size()] = 0;
211
212 // find CC dimensions used by the instrument
213 for (int cc = 0 ; cc < 128 ; cc++) {
214 for (std::vector<Region*>::const_iterator i = regions.begin() ;
215 i != regions.end() ; ++i) {
216 int lo = (*i)->locc[cc];
217 int hi = (*i)->hicc[cc]; // TODO == -1 ? 127 : (*i)->hicc[cc];
218 if (cc == triggercc) {
219 lo = std::max(lo, (*i)->on_locc[cc]);
220 hi = std::min(hi, (*i)->on_hicc[cc]);
221 }
222 if (lo > 0 || hi != 127) {
223 ccs.push_back(cc);
224 break;
225 }
226 }
227 }
228
229 // copy ccs vector to ccargs array
230 ccargs = new int[ccs.size() + 1];
231 for (std::vector<int>::size_type i = 0 ; i < ccs.size() ; ++i) {
232 dmsg(2,("ccargs %d: %d\n", int(i), ccs[i]));
233 ccargs[i] = ccs[i];
234 }
235 ccargs[ccs.size()] = -1;
236
237 int nbDimensions = int(dims.size() + ccs.size());
238 int* len = new int[nbDimensions];
239 mapArr = new int*[nbDimensions];
240
241 int size = 1;
242 int dim = 0;
243
244 // create and fill the dimension mapping arrays
245
246 for (std::vector<int>::const_iterator dimi = dims.begin() ;
247 dimi != dims.end() ; ++dimi) {
248 int min = dimDefs[*dimi].min;
249 int max = dimDefs[*dimi].max == -1 ? 127 : dimDefs[*dimi].max;
250 mapArr[dim] = new int[max - min + 1] - min;
251 len[dim] = fillMapArr(regions, dimDefs[*dimi].lo, dimDefs[*dimi].hi,
252 min, max, mapArr[dim]);
253 size *= len[dim];
254 dim++;
255 }
256
257 for (std::vector<int>::const_iterator cci = ccs.begin() ;
258 cci != ccs.end() ; ++cci) {
259 mapArr[dim] = new int[128];
260 len[dim] = fillMapArr(regions, *cci, mapArr[dim], triggercc);
261 size *= len[dim];
262 dim++;
263 }
264
265
266 dmsg(2,("-------------------------------\n"));
267 dmsg(2,("nbDimensions=%d size=%d\n", nbDimensions, size));
268
269 // create and fill the region array
270 regionArr = new LinuxSampler::ArrayList<Region*>[size];
271
272 for (std::vector<Region*>::const_iterator i = regions.begin() ;
273 i != regions.end() ; ++i) {
274 fillRegionArr(len, *i, 0, 0, triggercc);
275 }
276
277 // multiply the offsets in the mapping arrays so simple
278 // addition can be used in the query method
279 if (nbDimensions) {
280 int c = len[nbDimensions - 1];
281 for (dim = nbDimensions - 2 ; dim >= 0 ; dim--) {
282 int min;
283 int max;
284 if (dim < dims.size()) {
285 const DimDef& dimDef = dimDefs[dims[dim]];
286 min = dimDef.min;
287 max = dimDef.max == -1 ? 127 : dimDef.max;
288 } else {
289 min = 0;
290 max = 127;
291 }
292 for (int i = min ; i <= max ; i++) mapArr[dim][i] *= c;
293 c *= len[dim];
294 }
295 }
296
297 #if CONFIG_DEBUG_LEVEL >= 2
298 // print the dimension mapping arrays
299
300 dmsg(2,("-------------------------------\n"));
301 dim = 0;
302 for (std::vector<int>::const_iterator dimi = dims.begin() ;
303 dimi != dims.end() ; ++dimi) {
304 dmsg(2,("%d: len=%d dim=%s\n", dim, len[dim], dimDefs[*dimi].str));
305
306 int max = dimDefs[*dimi].max == -1 ? 127 : dimDefs[*dimi].max;
307 for (int i = dimDefs[*dimi].min ; i <= max ; i++) {
308 dmsg(2,(" %d", mapArr[dim][i]));
309 }
310 dmsg(2,("\n"));
311
312 dim++;
313 }
314 for (std::vector<int>::const_iterator cci = ccs.begin() ;
315 cci != ccs.end() ; ++cci) {
316 dmsg(2,("%d: len=%d cc=%d\n", dim, len[dim], *cci));
317
318 for (int i = 0 ; i < 128 ; i++) {
319 dmsg(2,(" %d", mapArr[dim][i]));
320 }
321 dmsg(2,("\n"));
322
323 dim++;
324 }
325 #endif
326 delete[] len;
327
328 #if CONFIG_DEBUG_LEVEL >= 3
329 // print the region array
330
331 int tot = 0;
332 for (int i = 0 ; i < size ; i++) {
333 dmsg(3,("%d:", i));
334 for (int j = 0 ; j < regionArr[i].size() ; j++) {
335 dmsg(3,(" %s", regionArr[i][j]->sample.c_str()));
336 tot++;
337 }
338 dmsg(3,("\n"));
339 }
340 dmsg(3,("tot=%d\n", tot));
341 #endif
342 }
343
344 LookupTable::~LookupTable() {
345 delete[] qargs;
346 delete[] ccargs;
347 delete[] regionArr;
348
349 int dim = 0;
350 for (std::vector<int>::const_iterator dimi = dims.begin() ;
351 dimi != dims.end() ; ++dimi) {
352 delete[] (mapArr[dim] + dimDefs[*dimi].min);
353 dim++;
354 }
355 for (std::vector<int>::const_iterator cci = ccs.begin() ;
356 cci != ccs.end() ; ++cci) {
357 delete[] mapArr[dim];
358 dim++;
359 }
360 delete[] mapArr;
361 }
362 }

  ViewVC Help
Powered by ViewVC