summaryrefslogtreecommitdiff
path: root/muse2/muse/ctrl.cpp
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
committerFlorian Jung <flo@windfisch.org>2012-07-01 16:42:16 +0000
commit9c4664d162c537ba4dd4fd8220971c0fb727103a (patch)
tree37a28b7cd4e4d8984ad4934a4884cd7b4da0505c /muse2/muse/ctrl.cpp
parente87fedf1be804f7ec774071d844b1f163be30b96 (diff)
final merge
Diffstat (limited to 'muse2/muse/ctrl.cpp')
-rw-r--r--muse2/muse/ctrl.cpp471
1 files changed, 453 insertions, 18 deletions
diff --git a/muse2/muse/ctrl.cpp b/muse2/muse/ctrl.cpp
index 8071491e..d7d42770 100644
--- a/muse2/muse/ctrl.cpp
+++ b/muse2/muse/ctrl.cpp
@@ -6,7 +6,7 @@
// controller handling for mixer automation
//
// (C) Copyright 2003 Werner Schweer (ws@seh.de)
-// (C) Copyright 2011 Time E. Real (terminator356 on users dot sourceforge dot net)
+// (C) Copyright 2011-2012 Tim E. Real (terminator356 on users dot sourceforge dot net)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -24,15 +24,20 @@
//
//=========================================================
+// Turn on debugging messages
+//#define _CTRL_DEBUG_
#include <QLocale>
#include <QColor>
+#include <map>
+
+#include <math.h>
#include "gconfig.h"
#include "fastlog.h"
-#include "math.h"
#include "globals.h"
#include "ctrl.h"
+#include "midictrl.h"
#include "xml.h"
namespace MusECore {
@@ -48,8 +53,268 @@ void CtrlList::initColor(int i)
_visible = false;
}
+//---------------------------------------------------------
+// midi2AudioCtrlValue
+// Apply mapper if it is non-null
+//---------------------------------------------------------
+
+double midi2AudioCtrlValue(const CtrlList* audio_ctrl_list, const MidiAudioCtrlStruct* /*mapper*/, int midi_ctlnum, int midi_val)
+{
+ double fmin, fmax;
+ audio_ctrl_list->range(&fmin, &fmax);
+ double frng = fmax - fmin; // The audio control range.
+
+ MidiController::ControllerType t = midiControllerType(midi_ctlnum);
+ CtrlValueType aud_t = audio_ctrl_list->valueType();
+
+ #ifdef _CTRL_DEBUG_
+ printf("midi2AudioCtrlValue: midi_ctlnum:%d val:%d fmin:%f fmax:%f\n", midi_ctlnum, midi_val, fmin, fmax);
+ #endif
+
+ int ctlmn = 0;
+ int ctlmx = 127;
+
+ int bval = midi_val;
+ switch(t)
+ {
+ case MidiController::RPN:
+ case MidiController::NRPN:
+ case MidiController::Controller7:
+ ctlmn = 0;
+ ctlmx = 127;
+ break;
+ case MidiController::Controller14:
+ case MidiController::RPN14:
+ case MidiController::NRPN14:
+ ctlmn = 0;
+ ctlmx = 16383;
+ break;
+ case MidiController::Program:
+ ctlmn = 0;
+ ctlmx = 0xffffff;
+ break;
+ case MidiController::Pitch:
+ ctlmn = -8192;
+ ctlmx = 8191;
+ bval += 8192;
+ break;
+ case MidiController::Velo: // cannot happen
+ default:
+ break;
+ }
+ double fictlrng = double(ctlmx - ctlmn); // Float version of the integer midi range.
+ double normval = double(bval) / fictlrng; // Float version of the normalized midi value.
+
+ // ---------- TODO: Do stuff with the mapper, if supplied.
+
+ if(aud_t == VAL_LOG)
+ {
+ // FIXME: Although this should be correct, some sliders show "---" at top end, some don't.
+ // Possibly because of use of fast_log10 in value(), and in sliders and automation IIRC.
+ fmin = 20.0*log10(fmin);
+ fmax = 20.0*log10(fmax);
+ frng = fmax - fmin;
+ double ret = exp10((normval * frng + fmin) / 20.0);
+ #ifdef _CTRL_DEBUG_
+ printf("midi2AudioCtrlValue: is VAL_LOG normval:%f frng:%f returning:%f\n", normval, frng, ret);
+ #endif
+ return ret;
+ }
+
+ if(aud_t == VAL_LINEAR)
+ {
+ double ret = normval * frng + fmin;
+ #ifdef _CTRL_DEBUG_
+ printf("midi2AudioCtrlValue: is VAL_LINEAR normval:%f frng:%f returning:%f\n", normval, frng, ret);
+ #endif
+ return ret;
+ }
+
+ if(aud_t == VAL_INT)
+ {
+ double ret = int(normval * frng + fmin);
+ #ifdef _CTRL_DEBUG_
+ printf("midi2AudioCtrlValue: is VAL_INT returning:%f\n", ret);
+ #endif
+ return ret;
+ }
+
+ if(aud_t == VAL_BOOL)
+ {
+ #ifdef _CTRL_DEBUG_
+ printf("midi2AudioCtrlValue: is VAL_BOOL\n");
+ #endif
+ //if(midi_val > ((ctlmx - ctlmn)/2 + ctlmn))
+ if((normval * frng + fmin) > (frng/2.0 + fmin))
+ return fmax;
+ else
+ return fmin;
+ }
+
+ printf("midi2AudioCtrlValue: unknown audio controller type:%d\n", aud_t);
+ return 0.0;
+}
+
+//---------------------------------------------------------
+// Midi to audio controller stuff
+//---------------------------------------------------------
+
+MidiAudioCtrlStruct::MidiAudioCtrlStruct()
+{
+ _audio_ctrl_id = 0;
+};
+
+MidiAudioCtrlStruct::MidiAudioCtrlStruct(int audio_ctrl_id) : _audio_ctrl_id(audio_ctrl_id)
+{
+};
+
+MidiAudioCtrlMap_idx_t MidiAudioCtrlMap::index_hash(int midi_port, int midi_chan, int midi_ctrl_num) const
+{
+ return ((MidiAudioCtrlMap_idx_t(midi_port) & 0xff) << 24) |
+ ((MidiAudioCtrlMap_idx_t(midi_chan) & 0xf) << 20) |
+ (MidiAudioCtrlMap_idx_t(midi_ctrl_num) & 0xfffff);
+}
+
+void MidiAudioCtrlMap::hash_values(MidiAudioCtrlMap_idx_t hash, int* midi_port, int* midi_chan, int* midi_ctrl_num) const
+{
+ if(midi_ctrl_num)
+ *midi_ctrl_num = hash & 0xfffff;
+ if(midi_chan)
+ *midi_chan = (hash >> 20) & 0xf;
+ if(midi_port)
+ *midi_port = (hash >> 24) & 0xff;
+}
+
+iMidiAudioCtrlMap MidiAudioCtrlMap::add_ctrl_struct(int midi_port, int midi_chan, int midi_ctrl_num,
+ const MidiAudioCtrlStruct& macs)
+{
+ MidiAudioCtrlMap_idx_t h = index_hash(midi_port, midi_chan, midi_ctrl_num);
+ std::pair<iMidiAudioCtrlMap, iMidiAudioCtrlMap> range = equal_range(h);
+ for(iMidiAudioCtrlMap imacp = range.first; imacp != range.second; ++imacp)
+ if(imacp->second.audioCtrlId() == macs.audioCtrlId())
+ return imacp;
+ return insert(std::pair<MidiAudioCtrlMap_idx_t, MidiAudioCtrlStruct >(h, macs));
+}
+void MidiAudioCtrlMap::erase_ctrl_struct(int midi_port, int midi_chan, int midi_ctrl_num, int audio_ctrl_id)
+{
+ MidiAudioCtrlMap_idx_t h = index_hash(midi_port, midi_chan, midi_ctrl_num);
+ std::pair<iMidiAudioCtrlMap, iMidiAudioCtrlMap> range = equal_range(h);
+ MidiAudioCtrlMap macm;
+ macm.insert(range.first, range.second);
+ for(iMidiAudioCtrlMap imacm = macm.begin(); imacm != macm.end(); ++imacm)
+ if(imacm->second.audioCtrlId() == audio_ctrl_id)
+ erase(imacm);
+}
+
+void MidiAudioCtrlMap::find_audio_ctrl_structs(int audio_ctrl_id, AudioMidiCtrlStructMap* amcs) //const
+{
+ for(iMidiAudioCtrlMap imacm = begin(); imacm != end(); ++imacm)
+ if(imacm->second.audioCtrlId() == audio_ctrl_id)
+ amcs->push_back(imacm);
+}
+
+void MidiAudioCtrlMap::write(int level, Xml& xml) const
+{
+ for(ciMidiAudioCtrlMap imacm = begin(); imacm != end(); ++imacm)
+ {
+ int port, chan, mctrl;
+ hash_values(imacm->first, &port, &chan, &mctrl);
+ int actrl = imacm->second.audioCtrlId();
+ QString s= QString("midiMapper port=\"%1\" ch=\"%2\" mctrl=\"%3\" actrl=\"%4\"")
+ .arg(port)
+ .arg(chan)
+ .arg(mctrl)
+ .arg(actrl);
+ xml.tag(level++, s.toAscii().constData());
+
+ // TODO
+ //const MidiAudioCtrlStruct& macs = imacs->second;
+ //xml.intTag(level, "macs ???", macs.);
+
+ xml.etag(level--, "midiMapper");
+ }
+}
+
+//---------------------------------------------------------
+// read
+//---------------------------------------------------------
+
+void MidiAudioCtrlMap::read(Xml& xml)
+ {
+ int port = -1, chan = -1, midi_ctrl = -1;
+ MidiAudioCtrlStruct macs(-1);
+
+ QLocale loc = QLocale::c();
+ bool ok;
+ int errcount = 0;
+ for (;;) {
+ Xml::Token token = xml.parse();
+ const QString& tag = xml.s1();
+ switch (token) {
+ case Xml::Error:
+ case Xml::End:
+ return;
+ case Xml::Attribut:
+ if (tag == "port")
+ {
+ port = loc.toInt(xml.s2(), &ok);
+ if(!ok)
+ {
+ ++errcount;
+ printf("MidiAudioCtrlPortMap::read failed reading port string: %s\n", xml.s2().toLatin1().constData());
+ }
+ }
+ else if (tag == "ch")
+ {
+ chan = loc.toInt(xml.s2(), &ok);
+ if(!ok)
+ {
+ ++errcount;
+ printf("MidiAudioCtrlPortMap::read failed reading ch string: %s\n", xml.s2().toLatin1().constData());
+ }
+ }
+ else if (tag == "mctrl")
+ {
+ midi_ctrl = loc.toInt(xml.s2(), &ok);
+ if(!ok)
+ {
+ ++errcount;
+ printf("MidiAudioCtrlPortMap::read failed reading mctrl string: %s\n", xml.s2().toLatin1().constData());
+ }
+ }
+ else if (tag == "actrl")
+ {
+ macs.setAudioCtrlId(loc.toInt(xml.s2(), &ok));
+ if(!ok)
+ {
+ ++errcount;
+ printf("MidiAudioCtrlPortMap::read failed reading actrl string: %s\n", xml.s2().toLatin1().constData());
+ }
+ }
+ else
+ printf("unknown tag %s\n", tag.toLatin1().constData());
+ break;
+ case Xml::TagStart:
+ // TODO
+ //if (tag == "???") {
+ // }
+ //else
+ xml.unknown("midiMapper");
+ break;
+ case Xml::TagEnd:
+ if (xml.s1() == "midiMapper")
+ {
+ if(errcount == 0 && port != -1 && chan != -1 && midi_ctrl != -1 && macs.audioCtrlId() != -1)
+ add_ctrl_struct(port, chan, midi_ctrl, macs);
+ return;
+ }
+ default:
+ break;
+ }
+ }
+ }
//---------------------------------------------------------
// CtrlList
//---------------------------------------------------------
@@ -62,6 +327,7 @@ CtrlList::CtrlList()
_mode = INTERPOLATE;
_dontShow = false;
_visible = false;
+ _guiUpdatePending = false;
initColor(0);
}
@@ -73,6 +339,7 @@ CtrlList::CtrlList(int id)
_mode = INTERPOLATE;
_dontShow = false;
_visible = false;
+ _guiUpdatePending = false;
initColor(id);
}
@@ -88,6 +355,7 @@ CtrlList::CtrlList(int id, QString name, double min, double max, CtrlValueType v
_valueType = v;
_dontShow = dontShow;
_visible = false;
+ _guiUpdatePending = false;
initColor(id);
}
@@ -115,39 +383,54 @@ void CtrlList::assign(const CtrlList& l, int flags)
if(flags & ASSIGN_VALUES)
{
*this = l; // Let the vector assign values.
+ _guiUpdatePending = true;
}
}
//---------------------------------------------------------
// value
+// Returns value at frame.
+// cur_val_only means read the current 'manual' value, not from the list even if it is not empty.
+// If passed a nextFrame, sets nextFrame to the next event frame, or -1 if no next frame (wide-open), or,
+// since CtrlList is a map, ZERO if should be replaced with some other frame by the caller (interpolation).
//---------------------------------------------------------
-double CtrlList::value(int frame) const
+double CtrlList::value(int frame, bool cur_val_only, int* nextFrame) const
{
- if(empty())
+ if(cur_val_only || empty())
+ {
+ if(nextFrame)
+ *nextFrame = -1;
return _curVal;
+ }
double rv;
- ciCtrl i = upper_bound(frame); // get the index after current frame
+ int nframe;
+ ciCtrl i = upper_bound(frame); // get the index after current frame
if (i == end()) { // if we are past all items just return the last value
--i;
- rv = i->second.val;
+ if(nextFrame)
+ *nextFrame = -1;
+ return i->second.val;
}
else if(_mode == DISCRETE)
{
if(i == begin())
{
+ nframe = i->second.frame;
rv = i->second.val;
}
else
{
+ nframe = i->second.frame;
--i;
rv = i->second.val;
}
}
- else {
+ else { // INTERPOLATE
if (i == begin()) {
+ nframe = i->second.frame;
rv = i->second.val;
}
else {
@@ -157,6 +440,12 @@ double CtrlList::value(int frame) const
int frame1 = i->second.frame;
double val1 = i->second.val;
+
+ if(val2 != val1)
+ nframe = 0; // Zero signifies the next frame should be determined by caller.
+ else
+ nframe = frame2;
+
if (_valueType == VAL_LOG) {
val1 = 20.0*fast_log10(val1);
if (val1 < MusEGlobal::config.minSlider)
@@ -166,10 +455,8 @@ double CtrlList::value(int frame) const
val2=MusEGlobal::config.minSlider;
}
- frame -= frame1;
val2 -= val1;
- frame2 -= frame1;
- val1 += (double(frame) * val2)/double(frame2);
+ val1 += (double(frame - frame1) * val2)/double(frame2 - frame1);
if (_valueType == VAL_LOG) {
val1 = exp10(val1/20.0);
@@ -178,6 +465,10 @@ double CtrlList::value(int frame) const
rv = val1;
}
}
+
+ if(nextFrame)
+ *nextFrame = nframe;
+
return rv;
}
@@ -196,7 +487,101 @@ double CtrlList::curVal() const
//---------------------------------------------------------
void CtrlList::setCurVal(double val)
{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::setCurVal val:%f\n", val);
+#endif
+
+ bool upd = (val != _curVal);
_curVal = val;
+ // If empty, any controller graphs etc. will be displaying this value.
+ // Otherwise they'll be displaying the list, so update is not required.
+ if(empty() && upd)
+ _guiUpdatePending = true;
+}
+
+//---------------------------------------------------------
+//
+// Catch all insert, erase, clear etc.
+//
+//---------------------------------------------------------
+
+CtrlList& CtrlList::operator=(const CtrlList& cl)
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::operator= id:%d\n", cl.id());
+#endif
+ std::map<int, CtrlVal, std::less<int> >::operator=(cl);
+ _guiUpdatePending = true;
+ return *this;
+}
+
+void CtrlList::swap(CtrlList& cl)
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::swap id:%d\n", cl.id());
+#endif
+ std::map<int, CtrlVal, std::less<int> >::swap(cl);
+ cl.setGuiUpdatePending(true);
+ _guiUpdatePending = true;
+}
+
+std::pair<iCtrl, bool> CtrlList::insert(const std::pair<int, CtrlVal>& p)
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::insert frame:%d val:%f\n", p.first, p.second.val);
+#endif
+ std::pair<iCtrl, bool> res = std::map<int, CtrlVal, std::less<int> >::insert(p);
+ _guiUpdatePending = true;
+ return res;
+}
+
+iCtrl CtrlList::insert(iCtrl ic, const std::pair<int, CtrlVal>& p)
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::insert2 frame:%d val:%f\n", p.first, p.second.val);
+#endif
+ iCtrl res = std::map<int, CtrlVal, std::less<int> >::insert(ic, p);
+ _guiUpdatePending = true;
+ return res;
+}
+
+void CtrlList::erase(iCtrl ictl)
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::erase iCtrl frame:%d val:%f\n", ictl->second.frame, ictl->second.val);
+#endif
+ std::map<int, CtrlVal, std::less<int> >::erase(ictl);
+ _guiUpdatePending = true;
+}
+
+std::map<int, CtrlVal, std::less<int> >::size_type CtrlList::erase(int frame)
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::erase frame:%d\n", frame);
+#endif
+ std::map<int, CtrlVal, std::less<int> >::size_type res = std::map<int, CtrlVal, std::less<int> >::erase(frame);
+ _guiUpdatePending = true;
+ return res;
+}
+
+void CtrlList::erase(iCtrl first, iCtrl last)
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::erase range first frame:%d val:%f second frame:%d val:%f\n",
+ first->second.frame, first->second.val,
+ last->second.frame, last->second.val);
+#endif
+ std::map<int, CtrlVal, std::less<int> >::erase(first, last);
+ _guiUpdatePending = true;
+}
+
+void CtrlList::clear()
+{
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::clear\n");
+#endif
+ std::map<int, CtrlVal, std::less<int> >::clear();
+ _guiUpdatePending = true;
}
//---------------------------------------------------------
@@ -208,7 +593,15 @@ void CtrlList::add(int frame, double val)
{
iCtrl e = find(frame);
if (e != end())
+ {
+ bool upd = (val != e->second.val);
e->second.val = val;
+#ifdef _CTRL_DEBUG_
+ printf("CtrlList::add frame:%d val:%f\n", frame, val);
+#endif
+ if(upd)
+ _guiUpdatePending = true;
+ }
else
insert(std::pair<const int, CtrlVal> (frame, CtrlVal(frame, val)));
}
@@ -234,7 +627,13 @@ void CtrlList::del(int frame)
void CtrlList::updateCurValue(int frame)
{
- _curVal = value(frame);
+ double v = value(frame);
+ bool upd = (v != _curVal);
+ _curVal = v;
+ // If empty, any controller graphs etc. will be displaying this value.
+ // Otherwise they'll be displaying the list, so update is not required.
+ if(empty() && upd)
+ _guiUpdatePending = true;
}
//---------------------------------------------------------
@@ -361,18 +760,23 @@ void CtrlListList::add(CtrlList* vl)
//---------------------------------------------------------
// value
+// Returns value at frame for controller with id ctrlId.
+// cur_val_only means read the current 'manual' value, not from the list even if it is not empty.
+// If passed a nextFrame, sets nextFrame to the next event frame, or -1 if no next frame (wide-open), or,
+// since CtrlList is a map, ZERO if should be replaced with some other frame by the caller (interpolation).
//---------------------------------------------------------
-double CtrlListList::value(int ctrlId, int frame, bool cur_val_only) const
+double CtrlListList::value(int ctrlId, int frame, bool cur_val_only, int* nextFrame) const
{
ciCtrlList cl = find(ctrlId);
if (cl == end())
- return 0.0;
-
- if(cur_val_only)
- return cl->second->curVal();
+ {
+ if(nextFrame)
+ *nextFrame = -1;
+ return 0.0;
+ }
- return cl->second->value(frame);
+ return cl->second->value(frame, cur_val_only, nextFrame);
}
//---------------------------------------------------------
@@ -391,5 +795,36 @@ void CtrlListList::updateCurValues(int frame)
for(ciCtrlList cl = begin(); cl != end(); ++cl)
cl->second->updateCurValue(frame);
}
-
+
+//---------------------------------------------------------
+// value
+//---------------------------------------------------------
+
+void CtrlListList::write(int level, Xml& xml) const
+{
+ for (ciCtrlList icl = begin(); icl != end(); ++icl) {
+ const CtrlList* cl = icl->second;
+
+ QString s= QString("controller id=\"%1\" cur=\"%2\"").arg(cl->id()).arg(cl->curVal()).toAscii().constData();
+ s += QString(" color=\"%1\" visible=\"%2\"").arg(cl->color().name()).arg(cl->isVisible());
+ xml.tag(level++, s.toAscii().constData());
+ int i = 0;
+ for (ciCtrl ic = cl->begin(); ic != cl->end(); ++ic) {
+ QString s("%1 %2, ");
+ xml.nput(level, s.arg(ic->second.frame).arg(ic->second.val).toAscii().constData());
+ ++i;
+ if (i >= 4) {
+ xml.put(level, "");
+ i = 0;
+ }
+ }
+ if (i)
+ xml.put(level, "");
+ xml.etag(level--, "controller");
+ }
+
+ _midi_controls.write(level, xml);
+}
+
+
} // namespace MusECore