1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: ctrl.cpp,v 1.1.2.4 2009/06/10 00:34:59 terminator356 Exp $
5 //
6 // controller handling for mixer automation
7 //
8 // (C) Copyright 2003 Werner Schweer (ws@seh.de)
9 // (C) Copyright 2011-2013 Tim E. Real (terminator356 on users dot sourceforge dot net)
10 //
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License
13 // as published by the Free Software Foundation; version 2 of
14 // the License, or (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 //
25 //=========================================================
26
27 // Turn on debugging messages
28 //#define _CTRL_DEBUG_
29
30 #include <QLocale>
31 #include <map>
32
33 #include "muse_math.h"
34 #include "gconfig.h"
35 #include "fastlog.h"
36 #include "globals.h"
37 #include "ctrl.h"
38 #include "midictrl.h"
39
40 // Forwards from header:
41 #include "xml.h"
42
43 namespace MusECore {
44
initColor(int i)45 void CtrlList::initColor(int i)
46 {
47 QColor collist[] = { Qt::red, Qt::yellow, Qt::blue , Qt::black, Qt::white, Qt::green };
48
49 if (i < 6)
50 _displayColor = collist[i%6];
51 else
52 _displayColor = Qt::green;
53 _visible = false;
54 }
55
56 //---------------------------------------------------------
57 // midi2AudioCtrlValue
58 // Apply mapper if it is non-null
59 //---------------------------------------------------------
60
midi2AudioCtrlValue(const CtrlList * audio_ctrl_list,const MidiAudioCtrlStruct *,int midi_ctlnum,int midi_val)61 double midi2AudioCtrlValue(const CtrlList* audio_ctrl_list, const MidiAudioCtrlStruct* /*mapper*/, int midi_ctlnum, int midi_val)
62 {
63 double fmin, fmax;
64 audio_ctrl_list->range(&fmin, &fmax);
65 double frng = fmax - fmin; // The audio control range.
66
67 MidiController::ControllerType t = midiControllerType(midi_ctlnum);
68 CtrlValueType aud_t = audio_ctrl_list->valueType();
69
70 #ifdef _CTRL_DEBUG_
71 printf("midi2AudioCtrlValue: midi_ctlnum:%d val:%d fmin:%f fmax:%f\n", midi_ctlnum, midi_val, fmin, fmax);
72 #endif
73
74 int ctlmn = 0;
75 int ctlmx = 127;
76
77 int bval = midi_val;
78 switch(t)
79 {
80 case MidiController::RPN:
81 case MidiController::NRPN:
82 case MidiController::Controller7:
83 ctlmn = 0;
84 ctlmx = 127;
85 break;
86 case MidiController::Controller14:
87 case MidiController::RPN14:
88 case MidiController::NRPN14:
89 ctlmn = 0;
90 ctlmx = 16383;
91 break;
92 case MidiController::Program:
93 ctlmn = 0;
94 ctlmx = 0xffffff;
95 break;
96 case MidiController::Pitch:
97 ctlmn = -8192;
98 ctlmx = 8191;
99 bval += 8192;
100 break;
101 case MidiController::Velo: // cannot happen
102 default:
103 break;
104 }
105
106 double fictlrng = double(ctlmx - ctlmn); // Float version of the integer midi range.
107 double normval = double(bval) / fictlrng; // Float version of the normalized midi value.
108
109 // ---------- TODO: Do stuff with the mapper, if supplied.
110
111 if(aud_t == VAL_LOG)
112 {
113 // FIXME: Although this should be correct, some sliders show "---" at top end, some don't.
114 // Possibly because of use of fast_log10 in value(), and in sliders and automation IIRC.
115 fmin = 20.0*log10(fmin);
116 fmax = 20.0*log10(fmax);
117 frng = fmax - fmin;
118 double ret = exp10((normval * frng + fmin) / 20.0);
119 #ifdef _CTRL_DEBUG_
120 printf("midi2AudioCtrlValue: is VAL_LOG normval:%f frng:%f returning:%f\n", normval, frng, ret);
121 #endif
122 return ret;
123 }
124
125 if(aud_t == VAL_LINEAR)
126 {
127 double ret = normval * frng + fmin;
128 #ifdef _CTRL_DEBUG_
129 printf("midi2AudioCtrlValue: is VAL_LINEAR normval:%f frng:%f returning:%f\n", normval, frng, ret);
130 #endif
131 return ret;
132 }
133
134 if(aud_t == VAL_INT)
135 {
136 double ret = int(normval * frng + fmin);
137 #ifdef _CTRL_DEBUG_
138 printf("midi2AudioCtrlValue: is VAL_INT returning:%f\n", ret);
139 #endif
140 return ret;
141 }
142
143 if(aud_t == VAL_BOOL)
144 {
145 #ifdef _CTRL_DEBUG_
146 printf("midi2AudioCtrlValue: is VAL_BOOL\n");
147 #endif
148 //if(midi_val > ((ctlmx - ctlmn)/2 + ctlmn))
149 if((normval * frng + fmin) > (frng/2.0 + fmin))
150 return fmax;
151 else
152 return fmin;
153 }
154
155 printf("midi2AudioCtrlValue: unknown audio controller type:%d\n", aud_t);
156 return 0.0;
157 }
158
159 //---------------------------------------------------------
160 // Midi to audio controller stuff
161 //---------------------------------------------------------
162
MidiAudioCtrlStruct()163 MidiAudioCtrlStruct::MidiAudioCtrlStruct()
164 {
165 _audio_ctrl_id = 0;
166 };
167
MidiAudioCtrlStruct(int audio_ctrl_id)168 MidiAudioCtrlStruct::MidiAudioCtrlStruct(int audio_ctrl_id) : _audio_ctrl_id(audio_ctrl_id)
169 {
170 };
171
index_hash(int midi_port,int midi_chan,int midi_ctrl_num) const172 MidiAudioCtrlMap_idx_t MidiAudioCtrlMap::index_hash(int midi_port, int midi_chan, int midi_ctrl_num) const
173 {
174 return ((MidiAudioCtrlMap_idx_t(midi_port) & 0xff) << 24) |
175 ((MidiAudioCtrlMap_idx_t(midi_chan) & 0xf) << 20) |
176 (MidiAudioCtrlMap_idx_t(midi_ctrl_num) & 0xfffff);
177 }
178
hash_values(MidiAudioCtrlMap_idx_t hash,int * midi_port,int * midi_chan,int * midi_ctrl_num) const179 void MidiAudioCtrlMap::hash_values(MidiAudioCtrlMap_idx_t hash, int* midi_port, int* midi_chan, int* midi_ctrl_num) const
180 {
181 if(midi_ctrl_num)
182 *midi_ctrl_num = hash & 0xfffff;
183 if(midi_chan)
184 *midi_chan = (hash >> 20) & 0xf;
185 if(midi_port)
186 *midi_port = (hash >> 24) & 0xff;
187 }
188
add_ctrl_struct(int midi_port,int midi_chan,int midi_ctrl_num,const MidiAudioCtrlStruct & macs)189 iMidiAudioCtrlMap MidiAudioCtrlMap::add_ctrl_struct(int midi_port, int midi_chan, int midi_ctrl_num,
190 const MidiAudioCtrlStruct& macs)
191 {
192 MidiAudioCtrlMap_idx_t h = index_hash(midi_port, midi_chan, midi_ctrl_num);
193 std::pair<iMidiAudioCtrlMap, iMidiAudioCtrlMap> range = equal_range(h);
194 for(iMidiAudioCtrlMap imacp = range.first; imacp != range.second; ++imacp)
195 if(imacp->second.audioCtrlId() == macs.audioCtrlId())
196 return imacp;
197 return insert(std::pair<MidiAudioCtrlMap_idx_t, MidiAudioCtrlStruct >(h, macs));
198 }
199
erase_ctrl_struct(int midi_port,int midi_chan,int midi_ctrl_num,int audio_ctrl_id)200 void MidiAudioCtrlMap::erase_ctrl_struct(int midi_port, int midi_chan, int midi_ctrl_num, int audio_ctrl_id)
201 {
202 MidiAudioCtrlMap_idx_t h = index_hash(midi_port, midi_chan, midi_ctrl_num);
203 std::pair<iMidiAudioCtrlMap, iMidiAudioCtrlMap> range = equal_range(h);
204 MidiAudioCtrlMap macm;
205 macm.insert(range.first, range.second);
206 for(iMidiAudioCtrlMap imacm = macm.begin(); imacm != macm.end(); ++imacm)
207 if(imacm->second.audioCtrlId() == audio_ctrl_id)
208 erase(imacm);
209 }
210
find_audio_ctrl_structs(int audio_ctrl_id,AudioMidiCtrlStructMap * amcs)211 void MidiAudioCtrlMap::find_audio_ctrl_structs(int audio_ctrl_id, AudioMidiCtrlStructMap* amcs) //const
212 {
213 for(iMidiAudioCtrlMap imacm = begin(); imacm != end(); ++imacm)
214 if(imacm->second.audioCtrlId() == audio_ctrl_id)
215 amcs->push_back(imacm);
216 }
217
write(int level,Xml & xml) const218 void MidiAudioCtrlMap::write(int level, Xml& xml) const
219 {
220 for(ciMidiAudioCtrlMap imacm = begin(); imacm != end(); ++imacm)
221 {
222 int port, chan, mctrl;
223 hash_values(imacm->first, &port, &chan, &mctrl);
224 int actrl = imacm->second.audioCtrlId();
225 QString s= QString("midiMapper port=\"%1\" ch=\"%2\" mctrl=\"%3\" actrl=\"%4\"")
226 .arg(port)
227 .arg(chan)
228 .arg(mctrl)
229 .arg(actrl);
230 xml.tag(level++, s.toLatin1().constData());
231
232 // TODO
233 //const MidiAudioCtrlStruct& macs = imacs->second;
234 //xml.intTag(level, "macs ???", macs.);
235
236 xml.etag(level--, "midiMapper");
237 }
238 }
239
240 //---------------------------------------------------------
241 // read
242 //---------------------------------------------------------
243
read(Xml & xml)244 void MidiAudioCtrlMap::read(Xml& xml)
245 {
246 int port = -1, chan = -1, midi_ctrl = -1;
247 MidiAudioCtrlStruct macs(-1);
248
249 QLocale loc = QLocale::c();
250 bool ok;
251 int errcount = 0;
252 for (;;) {
253 Xml::Token token = xml.parse();
254 const QString& tag = xml.s1();
255 switch (token) {
256 case Xml::Error:
257 case Xml::End:
258 return;
259 case Xml::Attribut:
260 if (tag == "port")
261 {
262 port = loc.toInt(xml.s2(), &ok);
263 if(!ok)
264 {
265 ++errcount;
266 printf("MidiAudioCtrlPortMap::read failed reading port string: %s\n", xml.s2().toLatin1().constData());
267 }
268 }
269 else if (tag == "ch")
270 {
271 chan = loc.toInt(xml.s2(), &ok);
272 if(!ok)
273 {
274 ++errcount;
275 printf("MidiAudioCtrlPortMap::read failed reading ch string: %s\n", xml.s2().toLatin1().constData());
276 }
277 }
278 else if (tag == "mctrl")
279 {
280 midi_ctrl = loc.toInt(xml.s2(), &ok);
281 if(!ok)
282 {
283 ++errcount;
284 printf("MidiAudioCtrlPortMap::read failed reading mctrl string: %s\n", xml.s2().toLatin1().constData());
285 }
286 }
287 else if (tag == "actrl")
288 {
289 macs.setAudioCtrlId(loc.toInt(xml.s2(), &ok));
290 if(!ok)
291 {
292 ++errcount;
293 printf("MidiAudioCtrlPortMap::read failed reading actrl string: %s\n", xml.s2().toLatin1().constData());
294 }
295 }
296 else
297 printf("unknown tag %s\n", tag.toLatin1().constData());
298 break;
299 case Xml::TagStart:
300 // TODO
301 //if (tag == "???") {
302 // }
303 //else
304 xml.unknown("midiMapper");
305 break;
306 case Xml::TagEnd:
307 if (xml.s1() == "midiMapper")
308 {
309 if(errcount == 0 && port != -1 && chan != -1 && midi_ctrl != -1 && macs.audioCtrlId() != -1)
310 add_ctrl_struct(port, chan, midi_ctrl, macs);
311 return;
312 }
313 default:
314 break;
315 }
316 }
317 }
318 //---------------------------------------------------------
319 // CtrlList
320 //---------------------------------------------------------
321
CtrlList(bool dontShow)322 CtrlList::CtrlList(bool dontShow)
323 {
324 _id = 0;
325 _default = 0.0;
326 _curVal = 0.0;
327 _mode = INTERPOLATE;
328 _dontShow = dontShow;
329 _visible = false;
330 _guiUpdatePending = false;
331 initColor(0);
332 }
333
CtrlList(int id,bool dontShow)334 CtrlList::CtrlList(int id, bool dontShow)
335 {
336 _id = id;
337 _default = 0.0;
338 _curVal = 0.0;
339 _mode = INTERPOLATE;
340 _dontShow = dontShow;
341 _visible = false;
342 _guiUpdatePending = false;
343 initColor(id);
344 }
345
CtrlList(int id,QString name,double min,double max,CtrlValueType v,bool dontShow)346 CtrlList::CtrlList(int id, QString name, double min, double max, CtrlValueType v, bool dontShow)
347 {
348 _id = id;
349 _default = 0.0;
350 _curVal = 0.0;
351 _mode = INTERPOLATE;
352 _name = name;
353 _min = min;
354 _max = max;
355 _valueType = v;
356 _dontShow = dontShow;
357 _visible = false;
358 _guiUpdatePending = false;
359 initColor(id);
360 }
361
CtrlList(const CtrlList & l,int flags)362 CtrlList::CtrlList(const CtrlList& l, int flags)
363 {
364 _id = l._id;
365 _valueType = l._valueType;
366 assign(l, flags | ASSIGN_PROPERTIES);
367 }
368
369 //---------------------------------------------------------
370 // assign
371 //---------------------------------------------------------
372
assign(const CtrlList & l,int flags)373 void CtrlList::assign(const CtrlList& l, int flags)
374 {
375 if(flags & ASSIGN_PROPERTIES)
376 {
377 _default = l._default;
378 _curVal = l._curVal;
379 _mode = l._mode;
380 _name = l._name;
381 _min = l._min;
382 _max = l._max;
383 _dontShow = l._dontShow;
384 _displayColor = l._displayColor;
385 _visible = l._visible;
386 }
387
388 if(flags & ASSIGN_VALUES)
389 {
390 CtrlList_t::operator=(l); // Let map copy the items.
391 _guiUpdatePending = true;
392 }
393 }
394
395 //---------------------------------------------------------
396 // getInterpolation
397 // Fills CtrlInterpolate struct for given frame.
398 // cur_val_only means read the current 'manual' value, not from the list even if it is not empty.
399 // CtrlInterpolate member eFrameValid can be false meaning no next value (wide-open, endless).
400 //---------------------------------------------------------
401
getInterpolation(unsigned int frame,bool cur_val_only,CtrlInterpolate * interp)402 void CtrlList::getInterpolation(unsigned int frame, bool cur_val_only, CtrlInterpolate* interp)
403 {
404 interp->eStop = false; // During processing, control FIFO ring buffers will set this true.
405
406 if(cur_val_only || empty())
407 {
408 interp->sFrame = 0;
409 interp->eFrame = 0;
410 interp->eFrameValid = false;
411 interp->sVal = _curVal;
412 interp->eVal = _curVal;
413 interp->doInterp = false;
414 return;
415 }
416 ciCtrl i = upper_bound(frame); // get the index after current frame
417 if (i == end()) // if we are past all items just return the last value
418 {
419 --i;
420 interp->sFrame = 0;
421 interp->eFrame = 0;
422 interp->eFrameValid = false;
423 interp->sVal = i->second.val;
424 interp->eVal = i->second.val;
425 interp->doInterp = false;
426 return;
427 }
428 else if(_mode == DISCRETE)
429 {
430 if(i == begin())
431 {
432 interp->sFrame = 0;
433 interp->eFrame = i->second.frame;
434 interp->eFrameValid = true;
435 interp->sVal = i->second.val;
436 interp->eVal = i->second.val;
437 interp->doInterp = false;
438 }
439 else
440 {
441 interp->eFrame = i->second.frame;
442 interp->eFrameValid = true;
443 interp->eVal = i->second.val;
444 --i;
445 interp->sFrame = i->second.frame;
446 interp->sVal = i->second.val;
447 interp->doInterp = false;
448 }
449 }
450 else // INTERPOLATE
451 {
452 if(i == begin())
453 {
454 interp->sFrame = 0;
455 interp->eFrame = i->second.frame;
456 interp->eFrameValid = true;
457 interp->sVal = i->second.val;
458 interp->eVal = i->second.val;
459 interp->doInterp = false;
460 }
461 else
462 {
463 interp->eFrame = i->second.frame;
464 interp->eFrameValid = true;
465 interp->eVal = i->second.val;
466 --i;
467 interp->sFrame = i->second.frame;
468 interp->sVal = i->second.val;
469 interp->doInterp = (interp->eVal != interp->sVal && interp->eFrame > interp->sFrame);
470 }
471 }
472 }
473
474 //---------------------------------------------------------
475 // interpolate
476 // Returns interpolated value at given frame, from a CtrlInterpolate struct.
477 // For speed, no checking is done for frame = frame2, val1 = val2 or even CtrlInterpolate::doInterp.
478 // Those are to be taken care of before calling this routine. See getInterpolation().
479 //---------------------------------------------------------
480
interpolate(unsigned int frame,const CtrlInterpolate & interp)481 double CtrlList::interpolate(unsigned int frame, const CtrlInterpolate& interp)
482 {
483 const unsigned int frame1 = interp.sFrame;
484 const unsigned int frame2 = interp.eFrame;
485 double val1 = interp.sVal;
486 double val2 = interp.eVal;
487 if(!interp.eFrameValid || frame >= frame2)
488 {
489 if(_valueType == VAL_LOG)
490 {
491 const double min = exp10(MusEGlobal::config.minSlider / 20.0); // TODO Try fastexp10
492 if(val2 < min)
493 val2 = min;
494 }
495 return val2;
496 }
497 if(frame <= frame1)
498 {
499 if(_valueType == VAL_LOG)
500 {
501 const double min = exp10(MusEGlobal::config.minSlider / 20.0); // TODO Try fastexp10
502 if(val1 < min)
503 val1 = min;
504 }
505 return val1;
506 }
507
508 if(_valueType == VAL_LOG)
509 {
510 val1 = 20.0*fast_log10(val1);
511 if (val1 < MusEGlobal::config.minSlider)
512 val1=MusEGlobal::config.minSlider;
513 val2 = 20.0*fast_log10(val2);
514 if (val2 < MusEGlobal::config.minSlider)
515 val2=MusEGlobal::config.minSlider;
516 }
517 val2 -= val1;
518 val1 += (double(frame - frame1) * val2) / double(frame2 - frame1);
519 if (_valueType == VAL_LOG)
520 val1 = exp10(val1/20.0);
521 return val1;
522 }
523
524 //---------------------------------------------------------
525 // value
526 // Returns value at frame.
527 // cur_val_only means read the current 'manual' value, not from the list even if it is not empty.
528 // If passed a nextFrame, sets nextFrame to the next event frame, or 0 and eFrameValid false if no next frame (wide-open), or,
529 // since CtrlList is a map, ZERO if should be replaced with some other frame by the caller (interpolation).
530 //---------------------------------------------------------
531
value(unsigned int frame,bool cur_val_only,unsigned int * nextFrame,bool * nextFrameValid) const532 double CtrlList::value(unsigned int frame, bool cur_val_only, unsigned int* nextFrame, bool* nextFrameValid) const
533 {
534 if(cur_val_only || empty())
535 {
536 if(nextFrameValid)
537 *nextFrameValid = false;
538 if(nextFrame)
539 *nextFrame = 0;
540 return _curVal;
541 }
542
543 double rv;
544 unsigned int nframe;
545
546 ciCtrl i = upper_bound(frame); // get the index after current frame
547 if (i == end()) { // if we are past all items just return the last value
548 --i;
549 if(nextFrameValid)
550 *nextFrameValid = false;
551 if(nextFrame)
552 *nextFrame = 0;
553 return i->second.val;
554 }
555 else if(_mode == DISCRETE)
556 {
557 if(i == begin())
558 {
559 nframe = i->second.frame;
560 rv = i->second.val;
561 }
562 else
563 {
564 nframe = i->second.frame;
565 --i;
566 rv = i->second.val;
567 }
568 }
569 else { // INTERPOLATE
570 if (i == begin()) {
571 nframe = i->second.frame;
572 rv = i->second.val;
573 }
574 else {
575 const unsigned int frame2 = i->second.frame;
576 double val2 = i->second.val;
577 --i;
578 const unsigned int frame1 = i->second.frame;
579 double val1 = i->second.val;
580
581
582 if(val2 != val1)
583 nframe = 0; // Zero signifies the next frame should be determined by caller.
584 else
585 nframe = frame2;
586
587 if (_valueType == VAL_LOG) {
588 val1 = 20.0*fast_log10(val1);
589 if (val1 < MusEGlobal::config.minSlider)
590 val1=MusEGlobal::config.minSlider;
591 val2 = 20.0*fast_log10(val2);
592 if (val2 < MusEGlobal::config.minSlider)
593 val2=MusEGlobal::config.minSlider;
594 }
595
596 val2 -= val1;
597 val1 += (double(frame - frame1) * val2)/double(frame2 - frame1);
598
599 if (_valueType == VAL_LOG) {
600 val1 = exp10(val1/20.0);
601 }
602
603 rv = val1;
604 }
605 }
606
607 if(nextFrame)
608 *nextFrame = nframe;
609 if(nextFrameValid)
610 *nextFrameValid = true;
611
612 return rv;
613 }
614
615 //---------------------------------------------------------
616 // curVal
617 // returns the static 'manual' value
618 //---------------------------------------------------------
curVal() const619 double CtrlList::curVal() const
620 {
621 return _curVal;
622 }
623
624 //---------------------------------------------------------
625 // setCurVal
626 // Sets the static 'manual' value
627 //---------------------------------------------------------
setCurVal(double val)628 void CtrlList::setCurVal(double val)
629 {
630 #ifdef _CTRL_DEBUG_
631 printf("CtrlList::setCurVal val:%f\n", val);
632 #endif
633
634 bool upd = (val != _curVal);
635 _curVal = val;
636 // If empty, any controller graphs etc. will be displaying this value.
637 // Otherwise they'll be displaying the list, so update is not required.
638 if(empty() && upd)
639 _guiUpdatePending = true;
640 }
641
642 //---------------------------------------------------------
643 //
644 // Catch all insert, erase, clear etc.
645 //
646 //---------------------------------------------------------
647
operator =(const CtrlList & cl)648 CtrlList& CtrlList::operator=(const CtrlList& cl)
649 {
650 #ifdef _CTRL_DEBUG_
651 printf("CtrlList::operator= id:%d\n", cl.id());
652 #endif
653 _id = cl._id;
654 _default = cl._default;
655 _curVal = cl._curVal;
656 _mode = cl._mode;
657 _name = cl._name;
658 _min = cl._min;
659 _max = cl._max;
660 _valueType = cl._valueType;
661 _dontShow = cl._dontShow;
662 _displayColor = cl._displayColor;
663 _visible = cl._visible;
664
665 // Let map copy the items.
666 CtrlList_t::operator=(cl);
667 _guiUpdatePending = true;
668 return *this;
669 }
670
swap(CtrlList & cl)671 void CtrlList::swap(CtrlList& cl)
672 {
673 #ifdef _CTRL_DEBUG_
674 printf("CtrlList::swap id:%d\n", cl.id());
675 #endif
676 CtrlList_t::swap(cl);
677 cl.setGuiUpdatePending(true);
678 _guiUpdatePending = true;
679 }
680
insert(const CtrlListInsertPair_t & p)681 std::pair<iCtrl, bool> CtrlList::insert(const CtrlListInsertPair_t& p)
682 {
683 #ifdef _CTRL_DEBUG_
684 printf("CtrlList::insert frame:%u val:%f\n", p.first, p.second.val);
685 #endif
686 std::pair<iCtrl, bool> res = CtrlList_t::insert(p);
687 _guiUpdatePending = true;
688 return res;
689 }
690
insert(iCtrl ic,const CtrlListInsertPair_t & p)691 iCtrl CtrlList::insert(iCtrl ic, const CtrlListInsertPair_t& p)
692 {
693 #ifdef _CTRL_DEBUG_
694 printf("CtrlList::insert2 frame:%u val:%f\n", p.first, p.second.val);
695 #endif
696 iCtrl res = CtrlList_t::insert(ic, p);
697 _guiUpdatePending = true;
698 return res;
699 }
700
insert(iCtrl first,iCtrl last)701 void CtrlList::insert(iCtrl first, iCtrl last)
702 {
703 #ifdef _CTRL_DEBUG_
704 printf("CtrlList::insert3 first frame:%u last frame:%d\n", first->first, last->first);
705 #endif
706 CtrlList_t::insert(first, last);
707 _guiUpdatePending = true;
708 }
709
erase(iCtrl ictl)710 void CtrlList::erase(iCtrl ictl)
711 {
712 #ifdef _CTRL_DEBUG_
713 printf("CtrlList::erase iCtrl frame:%u val:%f\n", ictl->second.frame, ictl->second.val);
714 #endif
715 CtrlList_t::erase(ictl);
716 _guiUpdatePending = true;
717 }
718
erase(unsigned int frame)719 CtrlList_t::size_type CtrlList::erase(unsigned int frame)
720 {
721 #ifdef _CTRL_DEBUG_
722 printf("CtrlList::erase frame:%u\n", frame);
723 #endif
724 size_type res = CtrlList_t::erase(frame);
725 _guiUpdatePending = true;
726 return res;
727 }
728
erase(iCtrl first,iCtrl last)729 void CtrlList::erase(iCtrl first, iCtrl last)
730 {
731 #ifdef _CTRL_DEBUG_
732 printf("CtrlList::erase range first frame:%u val:%f second frame:%u val:%f\n",
733 first->second.frame, first->second.val,
734 last->second.frame, last->second.val);
735 #endif
736 CtrlList_t::erase(first, last);
737 _guiUpdatePending = true;
738 }
739
clear()740 void CtrlList::clear()
741 {
742 #ifdef _CTRL_DEBUG_
743 printf("CtrlList::clear\n");
744 #endif
745 CtrlList_t::clear();
746 _guiUpdatePending = true;
747 }
748
749 //---------------------------------------------------------
750 // add
751 // Add, or replace, an event at time frame having value val.
752 //---------------------------------------------------------
753
add(unsigned int frame,double val)754 void CtrlList::add(unsigned int frame, double val)
755 {
756 iCtrl e = find(frame);
757 if (e != end())
758 {
759 bool upd = (val != e->second.val);
760 e->second.val = val;
761 #ifdef _CTRL_DEBUG_
762 printf("CtrlList::add frame:%u val:%f\n", frame, val);
763 #endif
764 if(upd)
765 _guiUpdatePending = true;
766 }
767 else
768 insert(CtrlListInsertPair_t(frame, CtrlVal(frame, val)));
769 }
770
771 //---------------------------------------------------------
772 // del
773 //---------------------------------------------------------
774
del(unsigned int frame)775 void CtrlList::del(unsigned int frame)
776 {
777 iCtrl e = find(frame);
778 if (e == end())
779 return;
780
781 erase(e);
782 }
783
784 //---------------------------------------------------------
785 // updateCurValues
786 // Set the current static 'manual' value (non-automation value)
787 // from the automation value at the given time.
788 //---------------------------------------------------------
789
updateCurValue(unsigned int frame)790 void CtrlList::updateCurValue(unsigned int frame)
791 {
792 double v = value(frame);
793 bool upd = (v != _curVal);
794 _curVal = v;
795 // If empty, any controller graphs etc. will be displaying this value.
796 // Otherwise they'll be displaying the list, so update is not required.
797 if(empty() && upd)
798 _guiUpdatePending = true;
799 }
800
801 //---------------------------------------------------------
802 // read
803 //---------------------------------------------------------
804
read(Xml & xml)805 void CtrlList::read(Xml& xml)
806 {
807 QLocale loc = QLocale::c();
808 bool ok;
809 for (;;) {
810 Xml::Token token = xml.parse();
811 const QString& tag = xml.s1();
812 switch (token) {
813 case Xml::Error:
814 case Xml::End:
815 return;
816 case Xml::Attribut:
817 if (tag == "id")
818 {
819 _id = loc.toInt(xml.s2(), &ok);
820 if(!ok)
821 printf("CtrlList::read failed reading _id string: %s\n", xml.s2().toLatin1().constData());
822 }
823 else if (tag == "cur")
824 {
825 _curVal = loc.toDouble(xml.s2(), &ok);
826 if(!ok)
827 printf("CtrlList::read failed reading _curVal string: %s\n", xml.s2().toLatin1().constData());
828 }
829 else if (tag == "visible")
830 {
831 _visible = loc.toInt(xml.s2(), &ok);
832 if(!ok)
833 printf("CtrlList::read failed reading _visible string: %s\n", xml.s2().toLatin1().constData());
834 }
835 else if (tag == "color")
836 {
837 ok = _displayColor.isValidColor(xml.s2());
838 if (!ok) {
839 printf("CtrlList::read failed reading color string: %s\n", xml.s2().toLatin1().constData());
840 break;
841 }
842 _displayColor.setNamedColor(xml.s2());
843 }
844 else
845 printf("unknown tag %s\n", tag.toLatin1().constData());
846 break;
847 case Xml::Text:
848 {
849 int len = tag.length();
850 unsigned int frame;
851 double val;
852
853 int i = 0;
854 for(;;)
855 {
856 while(i < len && (tag[i] == ',' || tag[i] == ' ' || tag[i] == '\n'))
857 ++i;
858 if(i == len)
859 break;
860
861 QString fs;
862 while(i < len && tag[i] != ' ')
863 {
864 fs.append(tag[i]);
865 ++i;
866 }
867 if(i == len)
868 break;
869
870 frame = loc.toUInt(fs, &ok);
871 if(!ok)
872 {
873 printf("CtrlList::read failed reading frame string: %s\n", fs.toLatin1().constData());
874 break;
875 }
876
877 while(i < len && (tag[i] == ' ' || tag[i] == '\n'))
878 ++i;
879 if(i == len)
880 break;
881
882 QString vs;
883 while(i < len && tag[i] != ' ' && tag[i] != ',')
884 {
885 vs.append(tag[i]);
886 ++i;
887 }
888
889 val = loc.toDouble(vs, &ok);
890 if(!ok)
891 {
892 printf("CtrlList::read failed reading value string: %s\n", vs.toLatin1().constData());
893 break;
894 }
895
896 // For now, the conversion only has a TEMPORARY effect during song loading.
897 // See comments in Song::read at the "samplerate" tag.
898 add(MusEGlobal::convertFrame4ProjectSampleRate(frame), val);
899
900 if(i == len)
901 break;
902 }
903 }
904 break;
905 case Xml::TagEnd:
906 if (xml.s1() == "controller")
907 return;
908 default:
909 break;
910 }
911 }
912 }
913
914 //---------------------------------------------------------
915 // add
916 //---------------------------------------------------------
917
add(CtrlList * vl)918 void CtrlListList::add(CtrlList* vl)
919 {
920 insert(std::pair<const int, CtrlList*>(vl->id(), vl));
921 }
922
923 //---------------------------------------------------------
924 // value
925 // Returns value at frame for controller with id ctrlId.
926 // cur_val_only means read the current 'manual' value, not from the list even if it is not empty.
927 // If passed a nextFrame, sets nextFrame to the next event frame, or 0 and eFrameValid false if no next frame (wide-open), or,
928 // since CtrlList is a map, ZERO if should be replaced with some other frame by the caller (interpolation).
929 //---------------------------------------------------------
930
value(int ctrlId,unsigned int frame,bool cur_val_only,unsigned int * nextFrame,bool * nextFrameValid) const931 double CtrlListList::value(int ctrlId, unsigned int frame, bool cur_val_only,
932 unsigned int* nextFrame, bool* nextFrameValid) const
933 {
934 ciCtrlList cl = find(ctrlId);
935 if (cl == end())
936 {
937 if(nextFrameValid)
938 *nextFrameValid = false;
939 if(nextFrame)
940 *nextFrame = 0;
941 return 0.0;
942 }
943
944 return cl->second->value(frame, cur_val_only, nextFrame, nextFrameValid);
945 }
946
947 //---------------------------------------------------------
948 // updateCurValues
949 // Set the current 'manual' values (non-automation values)
950 // from the automation values at the given time.
951 // This is typically called right after a track's automation type changes
952 // to OFF, so that the manual value becomes the last automation value.
953 // There are some interesting advantages to having completely independent
954 // 'manual' and automation values, but the jumping around when switching to OFF
955 // becomes disconcerting.
956 //---------------------------------------------------------
957
updateCurValues(unsigned int frame)958 void CtrlListList::updateCurValues(unsigned int frame)
959 {
960 for(ciCtrlList cl = begin(); cl != end(); ++cl)
961 cl->second->updateCurValue(frame);
962 }
963
964 //---------------------------------------------------------
965 // value
966 //---------------------------------------------------------
967
write(int level,Xml & xml) const968 void CtrlListList::write(int level, Xml& xml) const
969 {
970 for (ciCtrlList icl = begin(); icl != end(); ++icl) {
971 const CtrlList* cl = icl->second;
972
973 QString s= QString("controller id=\"%1\" cur=\"%2\"").arg(cl->id()).arg(cl->curVal());
974 s += QString(" color=\"%1\" visible=\"%2\"").arg(cl->color().name()).arg(cl->isVisible());
975 xml.tag(level++, s.toLatin1().constData());
976 int i = 0;
977 for (ciCtrl ic = cl->begin(); ic != cl->end(); ++ic) {
978 QString s("%1 %2, ");
979 xml.nput(level, s.arg(ic->second.frame).arg(ic->second.val).toLatin1().constData());
980 ++i;
981 if (i >= 4) {
982 xml.put(level, "");
983 i = 0;
984 }
985 }
986 if (i)
987 xml.put(level, "");
988 xml.etag(level--, "controller");
989 }
990
991 _midi_controls.write(level, xml);
992 }
993
994
995 } // namespace MusECore
996