diff options
author | Florian Jung <flo@windfisch.org> | 2012-07-01 16:42:16 +0000 |
---|---|---|
committer | Florian Jung <flo@windfisch.org> | 2012-07-01 16:42:16 +0000 |
commit | 9c4664d162c537ba4dd4fd8220971c0fb727103a (patch) | |
tree | 37a28b7cd4e4d8984ad4934a4884cd7b4da0505c /muse2/muse/ctrl.cpp | |
parent | e87fedf1be804f7ec774071d844b1f163be30b96 (diff) |
final merge
Diffstat (limited to 'muse2/muse/ctrl.cpp')
-rw-r--r-- | muse2/muse/ctrl.cpp | 471 |
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 |