I'm experimenting with external midi control for qtractor. For example, I have a midi device connected to qtractor that sends cc7 volume changes for a particular channel. Those changes doesn't seem to have any effect on qtractor, in the mixer the volume stays where it is. is there a way, perhaps, to enable such behavior so I could change channel volumes (and maybe other things) from external device?
Best regards,
Marko
patch for qtractorMainForm.cpp
I made a little patch, so that qtractor now happily obeys volume/pan controllers from my midi controller. I'm not sure this is "the right way" to do it. It is channel based, meaning that for every volume change received the program tries to find midi tracks corresponding to that channel. This may be a bit awkward, but I don't know how to do it otherwise. Also, qtractorTrackGainCommand with its redo/undo system is omitted; volume and pan is set directly through track->setPanning() and setVolume(). I did this because the first implementation had some feedback issues, events not coming back soon enough; there is a lot of happening if you push many faders at once :) I also had some crashes in appendMessages(), so I commented that out temporarily. Need to investigate that some more.
Below is what I added to void qtractorMainForm::midiControlEvent ( qtractorMidiControlEvent *pCtlEvent )
Bye, Marko
// handle volume controls if (pCtlEvent->controller() == 7) { for (int i = 0; i < m_pSession->tracks().count(); i++) { qtractorTrack* pTrack = m_pSession->tracks().at(i); if ( pTrack && (pTrack->trackType() == qtractorTrack::Midi) && pTrack->midiChannel() == pCtlEvent->channel()) { float fGain = float(pCtlEvent->value()) / 127.0f; // Set track gain directly bypassing undo/redo system // to avoid feedback issues with motorized external // controllers pTrack->setGain(fGain); qtractorMidiBus *pMidiBus = static_cast (pTrack->outputBus());
if (pMidiBus)
pMidiBus->setVolume(pTrack, fGain);
qtractorMixer *pMixer = mixer();
if (pMixer) {
qtractorMixerStrip *pStrip
= pMixer->trackRack()->findStrip(pTrack->monitor());
if (pStrip && pStrip->meter())
pStrip->meter()->updateGain();
}
sCtlText += tr("(track %1, gain %2)").arg(i).arg(fGain);
}
}
}
// handle pan controls
if (pCtlEvent->controller() == 10)
{
for (int i = 0; i < m_pSession->tracks().count(); i++)
{
qtractorTrack* pTrack = m_pSession->tracks().at(i);
if (
pTrack &&
(pTrack->trackType() == qtractorTrack::Midi) &&
pTrack->midiChannel() == pCtlEvent->channel())
{
float fPanning = (float(pCtlEvent->value()) - 63.0f) / 64.0f;
pTrack->setPanning(fPanning);
qtractorMidiBus *pMidiBus
= static_cast (pTrack->outputBus());
if (pMidiBus)
pMidiBus->setPanning(pTrack, fPanning);
qtractorMixer *pMixer = mixer();
if (pMixer) {
qtractorMixerStrip *pStrip
= pMixer->trackRack()->findStrip(pTrack->monitor());
if (pStrip && pStrip->meter())
pStrip->meter()->updatePanning();
}
sCtlText += tr("(track %1, panning %2)").arg(i).arg(fPanning);
}
}
}
Re: patch for qtractorMainForm.cpp
Hi Marko,
Awesome! It should work for the purpose at hand with flying colors :) I'll have the chance to take your code and commit to CVS as soon you give your blessing :)
// Handle volume controls... if (pCtlEvent->controller() == 7) { int iTrack = 0; for (qtractorTrack *pTrack = m_pSession->tracks().first(); pTrack; pTrack = pTrack->next()) { if (pTrack->trackType() == qtractorTrack::Midi && pTrack->midiChannel() == pCtlEvent->channel()) { float fGain = float(pCtlEvent->value()) / 127.0f; // Set track gain/volume directly, // bypassing the undo/redo system // to avoid feedback issues with // motorized external controllers... pTrack->setGain(fGain); qtractorMidiBus *pMidiBus = static_cast (pTrack->outputBus());
if (pMidiBus)
pMidiBus->setVolume(pTrack, fGain);
qtractorMixer *pMixer = mixer();
if (pMixer) {
qtractorMixerStrip *pStrip
= pMixer->trackRack()->findStrip(pTrack->monitor());
if (pStrip && pStrip->meter())
pStrip->meter()->updateGain();
}
sCtlText += tr("(track %1, gain %2)")
.arg(iTrack).arg(fGain);
}
++iTrack;
}
}
// Handle pan controls...
if (pCtlEvent->controller() == 10) {
int iTrack = 0;
for (qtractorTrack *pTrack = m_pSession->tracks().first();
pTrack; pTrack = pTrack->next()) {
if (pTrack->trackType() == qtractorTrack::Midi &&
pTrack->midiChannel() == pCtlEvent->channel()) {
// Set track panning directly,
// bypassing the undo/redo system
// to avoid feedback issues with
// motorized external controllers...
float fPanning = (float(pCtlEvent->value()) - 63.0f) / 64.0f;
pTrack->setPanning(fPanning);
qtractorMidiBus *pMidiBus
= static_cast (pTrack->outputBus());
if (pMidiBus)
pMidiBus->setPanning(pTrack, fPanning);
qtractorMixer *pMixer = mixer();
if (pMixer) {
qtractorMixerStrip *pStrip
= pMixer->trackRack()->findStrip(pTrack->monitor());
if (pStrip && pStrip->meter())
pStrip->meter()->updatePanning();
}
sCtlText += tr("(track %1, panning %2)")
.arg(iTrack).arg(fPanning);
}
iTrack++;
}
}
midi control
Hi,
I'm not sure it is CVS ready. I'm getting some really random crashes, meaning: sometimes none after 5 minute intensive control flood, other times immediately after moving one fader.
#0 0x00007fe0f8f8d5f4 in ?? () from /lib/libc.so.6
#1 0x00007fe0f8f8ba45 in memmove () from /lib/libc.so.6
#2 0x00007fe0fbb2253e in snd_seq_drain_output () from /usr/lib/libasound.so.2
#3 0x00000000004aef00 in qtractorMidiEngine::capture (this=0x297b500, pEv=0x2d52380) at src/qtractorMidiEngine.cpp:949
#4 0x00000000004b0b21 in qtractorMidiInputThread::run (this=0x2bf0a70) at src/qtractorMidiEngine.cpp:222
#5 0x00007fe0f9a90362 in ?? () from /usr/lib/libQtCore.so.4
#6 0x00007fe0fac043ea in start_thread () from /lib/libpthread.so.0
#7 0x00007fe0f8feec6d in clone () from /lib/libc.so.6
#8 0x0000000000000000 in ?? ()
But almost certainly there would be the following abort when exiting qtractor application. Note that this doesn't happen when not using bcf.
#0 0x00007f1226a7dfd5 in raise () from /lib/libc.so.6
#1 0x00007f1226a7fb43 in abort () from /lib/libc.so.6
#2 0x00007f1226abefa8 in ?? () from /lib/libc.so.6
#3 0x00007f1226ac4938 in ?? () from /lib/libc.so.6
#4 0x00007f1229665d3d in snd_seq_close () from /usr/lib/libasound.so.2
#5 0x00000000004ac6bc in qtractorMidiEngine::clean (this=0x1775740) at src/qtractorMidiEngine.cpp:1306
#6 0x0000000000465170 in qtractorEngine::close (this=0x1775740) at src/qtractorEngine.cpp:191
#7 0x00000000004fe58c in qtractorSession::close (this=0x17751b0) at src/qtractorSession.cpp:181
#8 0x0000000000565e60 in qtractorMainForm::closeSession (this=0x7fff31ce2880) at src/qtractorMainForm.cpp:1498
#9 0x000000000056818b in qtractorMainForm::queryClose (this=0x7fff31ce2880) atsrc/qtractorMainForm.cpp:915
#10 0x00000000005688fd in qtractorMainForm::closeEvent (this=0x7fff31ce2880, pCloseEvent=0x7fff31ce1cc0)
at src/qtractorMainForm.cpp:975
#11 0x00007f1227bc1da7 in QWidget::event () from /usr/lib/libQtGui.so.4
#12 0x00007f1227edaaab in QMainWindow::event () from /usr/lib/libQtGui.so.4
#13 0x00007f1227b6fc3d in QApplicationPrivate::notify_helper () from /usr/lib/libQtGui.so.4
#14 0x00007f1227b779ea in QApplication::notify () from /usr/lib/libQtGui.so.4
#15 0x00007f12276bbd61 in QCoreApplication::notifyInternal () from /usr/lib/libQtCore.so.4
#16 0x00007f1227bc4bea in QWidgetPrivate::close_helper () from /usr/lib/libQtGui.so.4
#17 0x00007f1227bc93a5 in QApplication::x11ClientMessage () from /usr/lib/libQtGui.so.4
#18 0x00007f1227bdae31 in QApplication::x11ProcessEvent () from /usr/lib/libQtGui.so.4
#19 0x00007f1227c022f4 in ?? () from /usr/lib/libQtGui.so.4
#20 0x00007f12253e4d3b in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#21 0x00007f12253e850d in ?? () from /usr/lib/libglib-2.0.so.0
#22 0x00007f12253e86cb in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0
#23 0x00007f12276e415f in QEventDispatcherGlib::processEvents () from /usr/lib/libQtCore.so.4
#24 0x00007f1227c01a9f in ?? () from /usr/lib/libQtGui.so.4
#25 0x00007f12276ba682 in QEventLoop::processEvents () from /usr/lib/libQtCore.so.4
#26 0x00007f12276ba80d in QEventLoop::exec () from /usr/lib/libQtCore.so.4
#27 0x00007f12276bccbd in QCoreApplication::exec () from /usr/lib/libQtCore.so.4
#28 0x0000000000429934 in main (argc=1, argv=0x7fff31ce2fe8) at src/main.cpp:283
Re: midi control
ouch. too late :) it's already committed to cvs (qtractor-0.2.2.1108+) no sweat.
hmm... i do have my doubts about these snippets, which might just be the root of your troubles. (wrt. volume here)
are you sure you want to send the events all through the output bus, again and replicated as many tracks of same MIDI channel there is? if you comment out those snippets, what do you get then?
P.S. incidentally I've just ordered a BCF2000; after it arrives I'll have all this troubles in first hand too :))
I thought I need that so
I thought I need that so external synths would get the volume change event?
I'll try without.
On the other hand, this implementation with midi channels has a drawback; you can't control audio tracks. However, I'm not aware of any standard that would be track based instead of channel based. And documentation on the topic seem to be scarce. I looked at your implementation for US-224, is that following any standard or is it just a tweak to make work? If it's a standard, perhaps it could be used also to control pan?
ad PS: Great news :)
Re: US-224
I believe the US-224 (and US-428) is trying to replicate the JL Cooper control surfaces protocol standards :)
byee
Re: midi control
You are right. Removing MidiBus->setVolume updates fixes my MidiEngine crashes. I removed it for pan, also. Works fine now. Thanks.
Re: midi control
Good to know. I'll remove from CVS as well :)) Anyway, as soon my BCF2000 gets into the picture (hopefully) I'll have a new approach on this MIDI control issues, specially regarding control feedback in for that (lovely) motorized faders :)
Cheers
BCF2000
Great news on the BCF2000 purchase. I too have a BCF2000 and have never used it within Linux. Perhaps soon I'll get the chance under Qtractor. :)
Lexridge
Re: BCF2000
Let's see what comes. I bought it on a ebay.co.uk auction and should arrive before this week-end, if the seller wants any kind of feedback :)
Cheers
Post new comment