//========================================================= // MusE // Linux Music Editor // $Id: transform.cpp,v 1.8 2005/11/17 18:19:30 wschweer Exp $ // // (C) Copyright 2001-2005 Werner Schweer (ws@seh.de) //========================================================= #include "midievent.h" #include "transform.h" static int eventTypeTable[] = { 1, 6, 4, 7, 8, 10, 11 }; static int procVal2Map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 10, 11 }; struct TDict { TransformFunction id; const QString text; TDict(TransformFunction f, const QString& s) : id(f), text(s) {} }; static const TDict oplist[] = { TDict(Trans, QString("Transform")), TDict(Delete, QString("Filter")) }; static const char* vall[] = { "c","c#","d","d#","e","f","f#","g","g#","a","a#","h" }; static const char* valu[] = { "C","C#","D","D#","E","F","F#","G","G#","A","A#","H" }; //--------------------------------------------------------- // pitch2string //--------------------------------------------------------- static QString pitch2string(int v) { if (v < 0 || v > 127) return QString("----"); int octave = (v / 12) - 2; QString o; o.sprintf("%d", octave); int i = v % 12; QString s(octave < 0 ? valu[i] : vall[i]); return s + o; } //--------------------------------------------------------- // Transform //--------------------------------------------------------- Transform::Transform(const char* name, const MempiHost* h) : Mempi(name, h) { } bool Transform::init() { gui = new TransformDialog(this, 0); gui->setWindowTitle(QString(name())); gui->show(); data.selEventOp = All; data.selType = 0x90; data.selVal1 = Ignore; data.selVal1a = 0; data.selVal1b = 0; data.selVal2 = Ignore; data.selVal2a = 0; data.selVal2b = 0; data.procEvent = Keep; data.eventType = 0x90; data.procVal1 = Keep; data.procVal1a = 0; data.procVal1b = 0; data.procVal2 = Keep; data.procVal2a = 0; data.procVal2b = 0; data.funcOp = Trans; data.quantVal = host->division(); data.selChannel = Ignore; data.selChannela = 0; data.selChannelb = 0; data.procChannel = Keep; data.procChannela = 0; data.procChannelb = 0; return false; } //--------------------------------------------------------- // filterValOp //--------------------------------------------------------- static bool filterValOp(ValOp op, int val, int val1, int val2) { switch (op) { case Ignore: break; case Equal: if (val != val1) return true; break; case Unequal: if (val == val1) return true; break; case Higher: if (val <= val1) return true; break; case Lower: if (val >= val1) return true; break; case Inside: if ((val < val1) || (val >= val2)) return true; break; case Outside: if ((val >= val1) && (val < val2)) return true; break; } return false; } //--------------------------------------------------------- // apply // apply Select filter // return 0 - not applied // 1 - drop event // 2 - event changed //--------------------------------------------------------- void Transform::process(unsigned, unsigned, MidiEventList* il, MidiEventList* ol) { for (iMidiEvent i = il->begin(); i != il->end(); ++i) { MidiEvent event(*i); if (filterEvent(event) == 1) continue; ol->insert(event); } } //--------------------------------------------------------- // filterEvent //--------------------------------------------------------- int Transform::filterEvent(MidiEvent& event) { switch (data.selEventOp) { case Equal: switch(event.type()) { case 0x90: case 0x80: if (data.selType != 0x90) return 0; break; default: if (event.type() != data.selType) return 0; break; } break; case Unequal: switch(event.type()) { case 0x90: case 0x80: if (data.selType == 0x90) return 0; break; default: if (event.type() == data.selType) return 0; break; } break; default: break; } if (filterValOp(data.selVal1, event.dataA(), data.selVal1a, data.selVal1b)) return 0; if (filterValOp(data.selVal2, event.dataB(), data.selVal2a, data.selVal2b)) return 0; if (filterValOp(data.selChannel, event.channel(), data.selChannela, data.selChannelb)) return 0; if (data.funcOp == Delete) return 1; // discard event // transform event if (data.procEvent != Keep) event.setType(data.eventType); //--------------------------------------------------- // transform value A //--------------------------------------------------- int val = event.dataA(); switch (data.procVal1) { case Keep: break; case Plus: val += data.procVal1a; break; case Minus: val -= data.procVal1a; break; case Multiply: val = int(val * (data.procVal1a/100.0) + .5); break; case Divide: val = int(val / (data.procVal1a/100.0) + .5); break; case Fix: val = data.procVal1a; break; case Value: val = data.procVal2a; break; case Invert: val = 127 - val; break; case ScaleMap: printf("scale map not implemented\n"); break; case Flip: val = data.procVal1a - val; break; case Dynamic: // "crescendo" printf("transform not implemented\n"); break; case Random: { int range = data.procVal1b - data.procVal1a; if (range > 0) val = (rand() % range) + data.procVal1a; else if (range < 0) val = (rand() % -range) + data.procVal1b; else val = data.procVal1a; } break; } if (val < 0) val = 0; if (val > 127) val = 127; event.setA(val); //--------------------------------------------------- // transform value B //--------------------------------------------------- val = event.dataB(); switch (data.procVal2) { case Plus: val += data.procVal2a; break; case Minus: val -= data.procVal2a; break; case Multiply: val = int(val * (data.procVal2a/100.0) + .5); break; case Divide: val = int(val / (data.procVal2a/100.0) + .5); break; case Fix: val = data.procVal2a; break; case Value: val = data.procVal1a; break; case Invert: val = 127 - val; break; case Dynamic: printf("transform not implemented\n"); break; case Random: { int range = data.procVal2b - data.procVal2a; if (range > 0) val = (rand() % range) + data.procVal2a; else if (range < 0) val = (rand() % -range) + data.procVal2b; else val = data.procVal2a; } break; case ScaleMap: case Keep: case Flip: break; } if (val < 0) val = 0; if (val > 127) val = 127; event.setB(val); //--------------------------------------------------- // transform channel //--------------------------------------------------- val = event.channel(); switch (data.procChannel) { case Plus: val += data.procChannela; break; case Minus: val -= data.procChannela; break; case Multiply: val = int(val * (data.procChannela/100.0) + .5); break; case Divide: val = int(val / (data.procChannela/100.0) + .5); break; case Fix: val = data.procChannela; break; case Value: val = data.procChannela; break; case Invert: val = 16 - val; break; case Dynamic: printf("transform not implemented\n"); break; case Random: { int range = data.procChannelb - data.procChannela; if (range > 0) val = (rand() % range) + data.procChannela; else if (range < 0) val = (rand() % -range) + data.procChannelb; else val = data.procChannela; } break; case ScaleMap: case Keep: case Flip: break; } if (val < 0) val = 0; if (val > 15) val = 15; event.setChannel(val); return 2; } //--------------------------------------------------------- // getGeometry //--------------------------------------------------------- void Transform::getGeometry(int* x, int* y, int* w, int* h) const { QPoint pos(gui->pos()); QSize size(gui->size()); *x = pos.x(); *y = pos.y(); *w = size.width(); *h = size.height(); } //--------------------------------------------------------- // setGeometry //--------------------------------------------------------- void Transform::setGeometry(int x, int y, int w, int h) { gui->resize(QSize(w, h)); gui->move(QPoint(x, y)); } //--------------------------------------------------------- // TransformDialog // Widgets: // selEventOp selType // selVal1Op selVal1a selVal1b // selVal2Op selVal2a selVal2b // // procEventOp procType // procVal1Op procVal1a procVal1b // procVal2Op procVal2a procVal2b // funcOp funcQuantVal // buttonNew buttonDelete // // selChannelOp selChannelVala selChannelValb // procChannelOp procChannelVala procChannelValb //--------------------------------------------------------- TransformDialog::TransformDialog(Transform* tf, QWidget* parent) : QDialog(parent) { setupUi(this); cmt = tf; for (unsigned i = 0; i < sizeof(oplist)/sizeof(*oplist); ++i) funcOp->addItem(oplist[i].text, i); connect(selEventOp, SIGNAL(activated(int)), SLOT(selEventOpSel(int))); connect(selType, SIGNAL(activated(int)), SLOT(selTypeSel(int))); connect(selVal1Op, SIGNAL(activated(int)), SLOT(selVal1OpSel(int))); connect(selVal2Op, SIGNAL(activated(int)), SLOT(selVal2OpSel(int))); connect(procEventOp, SIGNAL(activated(int)), SLOT(procEventOpSel(int))); connect(procType, SIGNAL(activated(int)), SLOT(procEventTypeSel(int))); connect(procVal1Op, SIGNAL(activated(int)), SLOT(procVal1OpSel(int))); connect(procVal2Op, SIGNAL(activated(int)), SLOT(procVal2OpSel(int))); connect(funcOp, SIGNAL(activated(int)), SLOT(funcOpSel(int))); connect(selVal1a, SIGNAL(valueChanged(int)), SLOT(selVal1aChanged(int))); connect(selVal1b, SIGNAL(valueChanged(int)), SLOT(selVal1bChanged(int))); connect(selVal2a, SIGNAL(valueChanged(int)), SLOT(selVal2aChanged(int))); connect(selVal2b, SIGNAL(valueChanged(int)), SLOT(selVal2bChanged(int))); connect(procVal1a, SIGNAL(valueChanged(int)), SLOT(procVal1aChanged(int))); connect(procVal1b, SIGNAL(valueChanged(int)), SLOT(procVal1bChanged(int))); connect(procVal2a, SIGNAL(valueChanged(int)), SLOT(procVal2aChanged(int))); connect(procVal2b, SIGNAL(valueChanged(int)), SLOT(procVal2bChanged(int))); connect(selChannelOp, SIGNAL(activated(int)), SLOT(selChannelOpSel(int))); connect(selChannelVala, SIGNAL(valueChanged(int)), SLOT(selChannelValaChanged(int))); connect(selChannelValb, SIGNAL(valueChanged(int)), SLOT(selChannelValbChanged(int))); connect(procChannelOp, SIGNAL(activated(int)), SLOT(procChannelOpSel(int))); connect(procChannelVala, SIGNAL(valueChanged(int)), SLOT(procChannelValaChanged(int))); connect(procChannelValb, SIGNAL(valueChanged(int)), SLOT(procChannelValbChanged(int))); } //--------------------------------------------------------- // init //--------------------------------------------------------- void TransformDialog::init() { selEventOp->setCurrentIndex(cmt->data.selEventOp); selEventOpSel(cmt->data.selEventOp); for (unsigned i = 0; i < sizeof(eventTypeTable)/sizeof(*eventTypeTable); ++i) { if (eventTypeTable[i] == cmt->data.selType) { selType->setCurrentIndex(i); break; } } selVal1Op->setCurrentIndex(cmt->data.selVal1); selVal1OpSel(cmt->data.selVal1); selVal2Op->setCurrentIndex(cmt->data.selVal2); selVal2OpSel(cmt->data.selVal2); selChannelOp->setCurrentIndex(cmt->data.selChannel); selChannelOpSel(cmt->data.selChannel); { unsigned i; for (i = 0; i < sizeof(oplist)/sizeof(*oplist); ++i) { if (oplist[i].id == cmt->data.funcOp) { funcOp->setCurrentIndex(i); break; } } if (i == sizeof(oplist)/sizeof(*oplist)) printf("internal error: bad OpCode\n"); funcOpSel(i); } procEventOp->setCurrentIndex(cmt->data.procEvent); procEventOpSel(cmt->data.procEvent); procVal1Op->setCurrentIndex(cmt->data.procVal1); procVal1OpSel(cmt->data.procVal1); for (unsigned i = 0; i < sizeof(procVal2Map)/sizeof(*procVal2Map); ++i) { if (procVal2Map[i] == cmt->data.procVal2) { procVal2Op->setCurrentIndex(i); break; } } selVal1a->setValue(cmt->data.selVal1a); selVal1b->setValue(cmt->data.selVal1b); selVal1aChanged(cmt->data.selVal1a); selVal1bChanged(cmt->data.selVal1b); selVal2a->setValue(cmt->data.selVal2a); selVal2b->setValue(cmt->data.selVal2b); selChannelVala->setValue(cmt->data.selChannela); selChannelValb->setValue(cmt->data.selChannelb); procVal1a->setValue(cmt->data.procVal1a); procVal1b->setValue(cmt->data.procVal1b); procVal2a->setValue(cmt->data.procVal2a); procVal2b->setValue(cmt->data.procVal2b); procChannelVala->setValue(cmt->data.procChannela); procChannelValb->setValue(cmt->data.procChannelb); } //--------------------------------------------------------- // setValOp //--------------------------------------------------------- void TransformDialog::setValOp(QWidget* a, QWidget* b, ValOp op) { switch (op) { case Ignore: a->setEnabled(false); b->setEnabled(false); break; case Equal: case Unequal: case Higher: case Lower: a->setEnabled(true); b->setEnabled(false); break; case Inside: case Outside: a->setEnabled(true); b->setEnabled(true); break; } } //--------------------------------------------------------- // selEventOpSel //--------------------------------------------------------- void TransformDialog::selEventOpSel(int val) { selType->setEnabled(val != All); cmt->data.selEventOp = ValOp(val); selVal1aChanged(cmt->data.selVal1a); selVal1bChanged(cmt->data.selVal1b); } //--------------------------------------------------------- // selTypeSel //--------------------------------------------------------- void TransformDialog::selTypeSel(int val) { cmt->data.selType = eventTypeTable[val]; selVal1aChanged(cmt->data.selVal1a); selVal1bChanged(cmt->data.selVal1b); } //--------------------------------------------------------- // selVal1OpSel //--------------------------------------------------------- void TransformDialog::selVal1OpSel(int val) { setValOp(selVal1a, selVal1b, ValOp(val)); cmt->data.selVal1 = ValOp(val); } //--------------------------------------------------------- // selVal2OpSel //--------------------------------------------------------- void TransformDialog::selVal2OpSel(int val) { setValOp(selVal2a, selVal2b, ValOp(val)); cmt->data.selVal2 = ValOp(val); } //--------------------------------------------------------- // procEventOpSel //--------------------------------------------------------- void TransformDialog::procEventOpSel(int val) { TransformOperator op = val == 0 ? Keep : Fix; procType->setEnabled(op == Fix); cmt->data.procEvent = op; } //--------------------------------------------------------- // procEventTypeSel //--------------------------------------------------------- void TransformDialog::procEventTypeSel(int val) { cmt->data.eventType = eventTypeTable[val]; } //--------------------------------------------------------- // procVal1OpSel //--------------------------------------------------------- void TransformDialog::procVal1OpSel(int val) { cmt->data.procVal1 = TransformOperator(val); switch(TransformOperator(val)) { case Keep: case Invert: procVal1a->setEnabled(false); procVal1b->setEnabled(false); break; case Multiply: case Divide: procVal1a->setEnabled(true); procVal1b->setEnabled(false); break; case Plus: case Minus: case Fix: case Value: case Flip: procVal1a->setEnabled(true); procVal1b->setEnabled(false); break; case Random: case ScaleMap: case Dynamic: procVal1a->setEnabled(true); procVal1b->setEnabled(true); break; } } //--------------------------------------------------------- // procVal2OpSel //--------------------------------------------------------- void TransformDialog::procVal2OpSel(int val) { TransformOperator op = TransformOperator(procVal2Map[val]); cmt->data.procVal2 = op; switch (op) { case Keep: case Invert: procVal2a->setEnabled(false); procVal2b->setEnabled(false); break; case Multiply: case Divide: procVal2a->setEnabled(true); procVal2b->setEnabled(false); break; case Plus: case Minus: case Fix: case Value: procVal2a->setEnabled(true); procVal2b->setEnabled(false); break; case Random: case Dynamic: procVal2a->setEnabled(true); procVal2b->setEnabled(true); break; default: break; } } //--------------------------------------------------------- // funcOpSel //--------------------------------------------------------- void TransformDialog::funcOpSel(int val) { TransformFunction op = oplist[val].id; bool isFuncOp(op == Trans); procEventOp->setEnabled(isFuncOp); procType->setEnabled(isFuncOp); procVal1Op->setEnabled(isFuncOp); procVal1a->setEnabled(isFuncOp); procVal1b->setEnabled(isFuncOp); procVal2Op->setEnabled(isFuncOp); procVal2a->setEnabled(isFuncOp); procVal2b->setEnabled(isFuncOp); procChannelOp->setEnabled(isFuncOp); procChannelVala->setEnabled(isFuncOp); procChannelValb->setEnabled(isFuncOp); if (isFuncOp) { procEventOpSel(cmt->data.procEvent); procVal1OpSel(cmt->data.procVal1); procVal2OpSel(cmt->data.procVal2); procChannelOpSel(cmt->data.procChannel); } cmt->data.funcOp = op; } //--------------------------------------------------------- // selVal1aChanged //--------------------------------------------------------- void TransformDialog::selVal1aChanged(int val) { cmt->data.selVal1a = val; if ((cmt->data.selEventOp != All) && (cmt->data.selType == 0x90)) { selVal1a->setSuffix(" - " + pitch2string(val)); } else selVal1a->setSuffix(QString("")); } //--------------------------------------------------------- // selVal1bChanged //--------------------------------------------------------- void TransformDialog::selVal1bChanged(int val) { cmt->data.selVal1b = val; if ((cmt->data.selEventOp != All) && (cmt->data.selType == 0x90)) { selVal1b->setSuffix(" - " + pitch2string(val)); } else selVal1b->setSuffix(QString("")); } //--------------------------------------------------------- // selVal2aChanged //--------------------------------------------------------- void TransformDialog::selVal2aChanged(int val) { cmt->data.selVal2a = val; } //--------------------------------------------------------- // selVal2bChanged //--------------------------------------------------------- void TransformDialog::selVal2bChanged(int val) { cmt->data.selVal2b = val; } //--------------------------------------------------------- // procVal1aChanged //--------------------------------------------------------- void TransformDialog::procVal1aChanged(int val) { cmt->data.procVal1a = val; } //--------------------------------------------------------- // procVal1bChanged //--------------------------------------------------------- void TransformDialog::procVal1bChanged(int val) { cmt->data.procVal1b = val; } //--------------------------------------------------------- // procVal2aChanged //--------------------------------------------------------- void TransformDialog::procVal2aChanged(int val) { cmt->data.procVal2a = val; } //--------------------------------------------------------- // procVal2bChanged //--------------------------------------------------------- void TransformDialog::procVal2bChanged(int val) { cmt->data.procVal2b = val; } //--------------------------------------------------------- // selChannelOpSel //--------------------------------------------------------- void TransformDialog::selChannelOpSel(int val) { setValOp(selChannelVala, selChannelValb, ValOp(val)); cmt->data.selChannel = ValOp(val); } //--------------------------------------------------------- // selChannelValaChanged //--------------------------------------------------------- void TransformDialog::selChannelValaChanged(int val) { cmt->data.selChannela = val; } //--------------------------------------------------------- // selChannelValbChanged //--------------------------------------------------------- void TransformDialog::selChannelValbChanged(int val) { cmt->data.selChannelb = val; } //--------------------------------------------------------- // procChannelOpSel //--------------------------------------------------------- void TransformDialog::procChannelOpSel(int val) { cmt->data.procChannel = TransformOperator(val); switch(TransformOperator(val)) { case Keep: case Invert: procChannelVala->setEnabled(false); procChannelValb->setEnabled(false); break; case Multiply: case Divide: procChannelVala->setEnabled(true); procChannelValb->setEnabled(false); break; case Plus: case Minus: case Fix: case Value: case Flip: procChannelVala->setEnabled(true); procChannelValb->setEnabled(false); break; case Random: case ScaleMap: case Dynamic: procChannelVala->setEnabled(true); procChannelValb->setEnabled(true); break; } } //--------------------------------------------------------- // procChannelValaChanged //--------------------------------------------------------- void TransformDialog::procChannelValaChanged(int val) { cmt->data.procChannela = val; } //--------------------------------------------------------- // procChannelValbChanged //--------------------------------------------------------- void TransformDialog::procChannelValbChanged(int val) { cmt->data.procChannelb = val; } //--------------------------------------------------------- // getInitData //--------------------------------------------------------- void Transform::getInitData(int* n, const unsigned char** p) const { *n = sizeof(data); *p = (unsigned char*)&data; } //--------------------------------------------------------- // setInitData //--------------------------------------------------------- void Transform::setInitData(int n, const unsigned char* p) { memcpy((void*)&data, p, n); if (gui) gui->init(); } //--------------------------------------------------------- // inst //--------------------------------------------------------- static Mempi* instantiate(const char* name, const MempiHost* h) { return new Transform(name, h); } extern "C" { static MEMPI descriptor = { "Transformator", "MusE Midi Event Transformator", "0.1", // version string MEMPI_FILTER, MEMPI_MAJOR_VERSION, MEMPI_MINOR_VERSION, instantiate }; const MEMPI* mempi_descriptor() { return &descriptor; } }