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