diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 07780f1..0d096af 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,13 @@ libcontrol/controlsender_test libgui/channelselector_test libgui/midicontrolchannelassigner_test libgui/slider_test +*.dot +*.tex +*.png +*.html +*.sty +*.svg +*.js +*.css +*.tmp +doxydoc/latex/Makefile diff --git a/INSTALL b/INSTALL index 41d3811..c1f31fc 100644 --- a/INSTALL +++ b/INSTALL @@ -18,3 +18,63 @@ If you run into any other problems don't hesitate to contact me at arnold@arnoldarts.de or on linux-audio-user@lists.linuxaudio.org. Problems involving the MIDI control of the mixer are almost certainly Nick Bailey's fault: nick@n-ism.org is the place to contact him. + +Install Scons + $ python3 -m pip install scons + +Install Qt environment + $ sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools + +Install the jack-audio-connection-kit and compile it. + $ git clone https://github.com/jackaudio/jack2.git + Or download the source code via the link below. + https://github.com/jackaudio/jack2/releases/tag/v1.9.21 + + Compile and install Jack2 , on linux, using './waf configure', './waf' and './waf install' as root. + On macosx, users can use the xcode project. + On Windows, users can use the Code::Blocks workspace (you also have a small script to make an all in one installer). + + Editing the configuration file + + If your system has no directory called /etc/security/limits.d then you will need to edit /etc/security/limits.conf. + If /etc/security/limits.d does exist on your machine, then you will need to create and edit a file called /etc/security/limits.d/audio.conf. + The file must contain (at least) the following two lines: + @audio - rtprio 95 + @audio - memlock unlimited + Contrary to a lot of misinformation on the web, there is no reason to include a line here that provides enhanced “niceness” control, + which is completely irrelevant for realtime scheduling and low latency audio applications. + + Creating an “audio” group + As the super-user (“root”) run the following commands from a terminal window: + $ sudo groupadd audio + $ sudo usermod -a -G audio yourUserID + Users should substitute their actual user id or “login” for “yourUserID”. + + Users can carry out these two steps using the graphical tools available under the “System Administration” section of your desktop’s main menu. However, this text-based method is faster and much easier to explain. + + Suppose users use a distribution that has already created the group and configured the “limits” file. + In that case, users will need to determine the name of the group (it is likely called “audio” or “jackuser”). + Then they can add themselves to the group with this command (run as the superuser inside a terminal window): + $ usermod -a -G theGroupName yourUserID + + Logout and back in + None of the changes users have made above will affect users until they log out and back in. + If that does not work, try rebooting. In either case, users do not need to reinstall any software. + +Install alsa, libsound2-dev, linux-lowlatency, pulseaudio-module-jack, qjackctl + $ sudo apt-get install alsa + $ sudo apt-get install libasound2-dev + $ sudo apt-get install linux-lowlatency + $ sudo apt-get install pulseaudio-module-jack + $ sudo apt-get install qjackctl + + After completing the above steps, run qjackctl. Qjackctl is the basis for Jackmix to run. + If qjackctl fails to run, Jackmix will not be available. + + +Complie and run Jackmix + The Jackmix project provides the SConstruct compilation file, so users can compile the entire Jackmix project + by typing scons in the terminal and pressing enter. Once compiled, the executable jackmix file is generated in + the /jackmix directory, and the graphical user interface appears after running jackmix successfully. + + diff --git a/backend/jack_backend.h b/backend/jack_backend.h index ebf20ad..75bf425 100644 --- a/backend/jack_backend.h +++ b/backend/jack_backend.h @@ -55,17 +55,37 @@ class JackBackend : public BackendInterface { JackBackend( GuiServer_Interface* ); /// Ends everything ~JackBackend(); - + + /** + * @brief Adding an output channel and return ture on success. + * @param Qstring The name of the output channel that we want to add. + * @return true or false + */ bool addOutput( QString ); + /** + * @brief Remove an input channel and return true on success. + * @param Qstring The name of the input channel that we want to remove. + * @return true or false + */ bool removeInput( QString ); + /** + * @brief Adding an input channel and return ture on success. + * @param Qstring The name of the input channel that we want to add. + * @return true or false + */ bool addInput( QString ); + /** + * @brief Remove an input channel and return true on success. + * @param Qstring The name of the input channel that we want to remove. + * @return true or false + */ bool removeOutput( QString ); /** - * Rename a jack port + * @brief Rename a jack port * - * \param old_name current port name - * \param new_name new port name - * \returns whether a port was renamed + * @param old_name current port name + * @param new_name new port name + * @returns whether a port was renamed */ bool rename(const QString old_name, const QString new_name); bool rename(const QString old_name, const char *new_name); @@ -120,7 +140,7 @@ class JackBackend : public BackendInterface { ::jack_port_t *midi_port; /** - * Handle changes in jack server sample rate + * @brief Handle changes in jack server sample rate * * @param rate New sample rate * @param args Client-supplied args (not used) diff --git a/jackmix/1.jm-xml b/jackmix/1.jm-xml new file mode 100644 index 0000000..060a0b3 --- /dev/null +++ b/jackmix/1.jm-xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jackmix/mainwindow.cpp b/jackmix/mainwindow.cpp index 3b17e7f..c0c2622 100644 --- a/jackmix/mainwindow.cpp +++ b/jackmix/mainwindow.cpp @@ -121,6 +121,7 @@ void MainWindow::init() { _filemenu->addAction( "Save File...", this, SLOT( saveFile() ), Qt::CTRL+Qt::Key_S ); _filemenu->addSeparator(); _filemenu->addAction( "&Quit", this, SLOT( close() ), Qt::CTRL+Qt::Key_Q ); + _editmenu = menuBar()->addMenu( "&Edit" ); _select_action = new QAction( "Select Mode", this ); @@ -130,24 +131,34 @@ void MainWindow::init() { //_select_action->addTo( new QToolBar( this ) ); _editmenu->addAction( "&Fill empty spaces", this, SLOT( scheduleAutoFill() ) ); _editmenu->addSeparator(); + _add_inchannel_action = new QAction( "Add &Input...", this ); connect( _add_inchannel_action, SIGNAL( triggered() ), this, SLOT( addInput() ) ); _editmenu->addAction( _add_inchannel_action ); + _add_outchannel_action = new QAction( "Add &Output...", this ); connect( _add_outchannel_action, SIGNAL( triggered() ), this, SLOT( addOutput() ) ); _editmenu->addAction( _add_outchannel_action ); + _rename_input_action = new QAction( "Re&name Inputs...", this); connect( _rename_input_action, SIGNAL( triggered() ), this, SLOT(renameInput()) ); _editmenu->addAction( _rename_input_action ); + _rename_output_action = new QAction( "Ren&ame Outputs...", this); connect( _rename_output_action, SIGNAL( triggered() ), this, SLOT(renameOutput()) ); _editmenu->addAction( _rename_output_action ); + _remove_inchannel_action = new QAction( "&Remove Input...", this ); connect( _remove_inchannel_action, SIGNAL( triggered() ), this, SLOT( removeInput() ) ); _editmenu->addAction( _remove_inchannel_action ); + _remove_outchannel_action = new QAction( "R&emove Output...", this ); connect( _remove_outchannel_action, SIGNAL( triggered() ), this, SLOT( removeOutput() ) ); _editmenu->addAction( _remove_outchannel_action ); + + //_replace_action = new QAction( "Replace elements...", this ); + //connect( _replace_action, SIGNAL( triggered() ), this, SLOT( slot_simple_select())); + //_editmenu->addAction(_replace_action); _viewmenu = menuBar()->addMenu( "&View" ); _togglein_action = new QAction( "Hide &inputcontrols", this ); diff --git a/jackmix/mainwindow.h b/jackmix/mainwindow.h index 02beea5..b678ca0 100644 --- a/jackmix/mainwindow.h +++ b/jackmix/mainwindow.h @@ -31,7 +31,7 @@ #include #include #include - +#include #include "controlsender.h" class QHBox; @@ -100,6 +100,8 @@ private slots: void removeOutput(); void removeOutput( QString ); + //void slot_simple_replace(); + void allAutoFill(); void scheduleAutoFill(); diff --git a/libelements/aux_elements.cpp b/libelements/aux_elements.cpp index e713112..4b569bb 100644 --- a/libelements/aux_elements.cpp +++ b/libelements/aux_elements.cpp @@ -32,7 +32,9 @@ #include #include #include -//#include +#include +#include +#include #include #include @@ -77,12 +79,19 @@ AuxElement::AuxElement( QStringList inchannel, QStringList outchannel, MixingMat : Element( inchannel, outchannel, p, n ) , dB2VolCalc( -42, 6 ) { + if (p->mode() == Widget::Select) { menu()->addAction( "Select", this, SLOT( slot_simple_select() ) ); - menu()->addAction( "Replace", this, SLOT( slot_simple_replace() ) ); + + menu()->addAction( "&Replace", this, SLOT( slot_simple_replace() ), Qt::Key_R ); + + _button = new QRadioButton(this); + connect(_button, SIGNAL(clicked()),this,SLOT(slot_simple_select())); } - menu()->addAction( "Assign MIDI Parameter", this, SLOT( slot_assign_midi_parameters() ) ); + + menu()->addAction( "&Assign MIDI Parameter", this, SLOT( slot_assign_midi_parameters() ) ); + QVBoxLayout* _layout = new QVBoxLayout( this ); if ( _in[0] == _out[0] ) { @@ -93,8 +102,12 @@ AuxElement::AuxElement( QStringList inchannel, QStringList outchannel, MixingMat _poti = new JackMix::GUI::Knob( amptodb( backend()->getVolume( _in[0], _out[0] ) ), dbmin, dbmax, 2, 3, this ); - _layout->addWidget( _poti, 100 ); - + + //_button = new QRadioButton(this); + + _layout->addWidget( _poti, 2000 ); + + //connect(_button, SIGNAL(buttonClicked()),this,SLOT(slot_simple_select())); connect( _poti, SIGNAL( valueChanged( double ) ), this, SLOT( emitvalue( double ) ) ); connect( _poti, SIGNAL( select() ), this, SLOT( slot_simple_select() ) ); connect( _poti, SIGNAL( replace() ), this, SLOT( slot_simple_replace() ) ); diff --git a/libelements/aux_elements.h b/libelements/aux_elements.h index 8a00f92..2d3033a 100644 --- a/libelements/aux_elements.h +++ b/libelements/aux_elements.h @@ -29,7 +29,7 @@ #include #include #include - +#include namespace JackMix { namespace GUI { @@ -53,12 +53,17 @@ Q_OBJECT int outchannels() const { return 1; } void setIndicator(const QColor& c); - + +signals: + public slots: + + void emitvalue( double ); private: JackMix::GUI::Knob *_poti; + QRadioButton *_button; }; void init_aux_elements(); diff --git a/libelements/stereo_elements.cpp b/libelements/stereo_elements.cpp index f085611..3e07798 100644 --- a/libelements/stereo_elements.cpp +++ b/libelements/stereo_elements.cpp @@ -49,11 +49,12 @@ class StereoFactory : public JackMix::MixingMatrix::ElementFactory ~StereoFactory() {} QStringList canCreate() const { - return QStringList()<<"Mono2StereoElement"<<"Stereo2StereoElement"; + return QStringList()<<"Mono2StereoElement"<<"Stereo2StereoElement"<<"Threeinput2outputElement"; } QStringList canCreate( int in, int out ) const { if ( in==1 && out==2 ) return QStringList()<<"Mono2StereoElement"; if ( in==2 && out==2 ) return QStringList()<<"Stereo2StereoElement"; + if ( in==3 && out==2 ) return QStringList()<<"Threeinput2outputElement"; return QStringList(); } @@ -62,6 +63,8 @@ class StereoFactory : public JackMix::MixingMatrix::ElementFactory return new Mono2StereoElement( ins, outs, p, n ); if ( type=="Stereo2StereoElement" ) return new Stereo2StereoElement( ins, outs, p, n ); + if ( type=="Threeinput2outputElement" ) + return new Threeinput2outputElement( ins, outs, p, n ); return 0; } }; @@ -93,10 +96,7 @@ Mono2StereoElement::Mono2StereoElement( QStringList inchannel, QStringList outch _layout->setMargin( 0 ); _layout->setSpacing( 0 ); - menu()->addAction( "Select", this, SLOT( slot_simple_select() ) ); - menu()->addAction( "Replace", this, SLOT( slot_simple_replace() ) ); - menu()->addAction( "Explode", this, SLOT( slot_simple_explode() ) ); - menu()->addAction( "Assign MIDI Parameter", this, SLOT( slot_assign_midi_parameters() ) ); + _balance = new JackMix::GUI::Knob( _balance_value, -1, 1, 2, 0.1, this, "%1" ); _layout->addWidget( _balance, 10 ); @@ -109,6 +109,12 @@ Mono2StereoElement::Mono2StereoElement( QStringList inchannel, QStringList outch connect( _volume, SIGNAL( select() ), this, SLOT( slot_simple_select() ) ); connect( _volume, SIGNAL( replace() ), this, SLOT( slot_simple_replace() ) ); + menu()->addAction( "Select", this, SLOT( slot_simple_select() ) ); + menu()->addAction( "&Replace", this, SLOT( slot_simple_replace() ) ); + menu()->addAction( "&Explode", this, SLOT( slot_simple_explode() ) ); + menu()->addAction( "&Assign MIDI Parameter", this, SLOT( slot_assign_midi_parameters() ) ); + + // WATCH OUT: Order of initialisation is really important! // Make sure all the widgets are contructed before adding them to the delegates list @@ -132,14 +138,14 @@ Mono2StereoElement::~Mono2StereoElement() { } void Mono2StereoElement::balance( double n ) { - //qDebug( "Mono2StereoElement::balance( double %f )", n ); + qDebug( "Mono2StereoElement::balance( double %f )", n ); _balance_value = n; calculateVolumes(); _balance->value( n ); emit valueChanged( this, QString( "balance" ) ); } void Mono2StereoElement::volume( double n ) { - //qDebug( "Mono2StereoElement::volume( double %f )", n ); + qDebug( "Mono2StereoElement::volume( double %f )", n ); _volume_value = n; calculateVolumes(); _volume->value( n ); @@ -195,14 +201,18 @@ Stereo2StereoElement::Stereo2StereoElement( QStringList inchannels, QStringList QAction *toggle = new QAction( "Toggle Selection", this ); connect( toggle, SIGNAL( triggered() ), this, SLOT( slot_simple_select() ) ); menu()->addAction( toggle ); - QAction *replace = new QAction( "Replace", this ); + + QAction *replace = new QAction( "&Replace", this ); connect( replace, SIGNAL( triggered() ), this, SLOT( slot_simple_replace() ) ); menu()->addAction( replace ); - QAction *explode = new QAction( "Explode", this ); + + QAction *explode = new QAction( "&Explode", this ); + explode->setShortcut(Qt::CTRL+Qt::Key_E); + this->addAction(explode); connect( explode, SIGNAL( triggered() ), this, SLOT( slot_simple_explode() ) ); menu()->addAction( explode ); - QAction *assign = new QAction( "Assign MIDI Parameter", this ); + QAction *assign = new QAction( "&Assign MIDI Parameter", this ); connect( assign, SIGNAL( triggered() ), this, SLOT( slot_assign_midi_parameters() ) ); menu()->addAction( assign ); @@ -231,14 +241,14 @@ Stereo2StereoElement::~Stereo2StereoElement() { } void Stereo2StereoElement::balance( double n ) { - //qDebug( "Mono2StereoElement::balance( double %f )", n ); + qDebug( "Mono2StereoElement::balance( double %f )", n ); _balance_value = n; _balance_widget->value( n ); calculateVolumes(); emit valueChanged( this, QString( "balance" ) ); } void Stereo2StereoElement::volume( double n ) { - //qDebug( "Mono2StereoElement::volume( double %f )", n ); + qDebug( "Mono2StereoElement::volume( double %f )", n ); _volume_value = n; _volume_widget->value( n ); calculateVolumes(); @@ -256,3 +266,192 @@ void Stereo2StereoElement::calculateVolumes() { backend()->setVolume( _in[0], _out[0], left ); backend()->setVolume( _in[1], _out[1], right ); } + + + + + + +Threeinput2outputElement::Threeinput2outputElement( QStringList inchannel, QStringList outchannels, MixingMatrix::Widget* p, const char* n ) + : Element( inchannel, outchannels, p, n ) + , dB2VolCalc(-42, 6 ) + , _balance_value( 0 ) + , _volume_value( 0 ) + , _balance_value2( 0 ) + , _volume_value2( 0 ) + , _balance_value3( 0 ) + , _volume_value3( 0 ) +{ + + double left = backend()->getVolume( _in[0], _out[0] ); + double right = backend()->getVolume( _in[0], _out[1] ); + //qDebug( " volumes: %f, %f", left, right ); + if ( left>right ) { + _volume_value = left; + _balance_value = right-left; + } else { + _volume_value = right; + _balance_value = right-left; + } + double left2 = backend()->getVolume( _in[1], _out[0] ); + double right2 = backend()->getVolume( _in[1], _out[1] ); + //qDebug( " volumes: %f, %f", left, right ); + if ( left2>right2 ) { + _volume_value2 = left2; + _balance_value2 = right2-left2; + } else { + _volume_value2 = right2; + _balance_value2 = right2-left2; + } + double left3 = backend()->getVolume( _in[2], _out[0] ); + double right3 = backend()->getVolume( _in[2], _out[1] ); + //qDebug( " volumes: %f, %f", left, right ); + if ( left3>right3 ) { + _volume_value3 = left3; + _balance_value3 = right3-left3; + } else { + _volume_value3 = right3; + _balance_value3 = right3-left3; + } + //qDebug( " values: %f, %f", _volume_value, _balance_value ); + QGridLayout* _layout = new QGridLayout( this ); + _layout->setSpacing( 1 ); + _layout->setMargin( 2 ); + + _balance = new JackMix::GUI::Knob( _balance_value, -1, 1, 2, 0.1, this, "%1" ); + _layout->addWidget( _balance, 0,0,1,1 ); + _layout->setRowStretch( 0, 255 ); + connect( _balance, SIGNAL( valueChanged( double ) ), this, SLOT( balance( double ) ) ); + connect( _balance, SIGNAL( select() ), this, SLOT( slot_simple_select() ) ); + connect( _balance, SIGNAL( replace() ), this, SLOT( slot_simple_replace() ) ); + + _balance2 = new JackMix::GUI::Knob( _balance_value2, -1, 1, 2, 0.1, this, "%1" ); + _layout->addWidget( _balance2, 0,1,1,1 ); + _layout->setRowStretch( 0, 255 ); + connect( _balance2, SIGNAL( valueChanged( double ) ), this, SLOT( balance2( double ) ) ); + connect( _balance2, SIGNAL( select() ), this, SLOT( slot_simple_select() ) ); + connect( _balance2, SIGNAL( replace() ), this, SLOT( slot_simple_replace() ) ); + + _balance3 = new JackMix::GUI::Knob( _balance_value3, -1, 1, 2, 0.1, this, "%1" ); + _layout->addWidget( _balance3, 0,2,1,1 ); + _layout->setRowStretch( 0, 255 ); + connect( _balance3, SIGNAL( valueChanged( double ) ), this, SLOT( balance3( double ) ) ); + connect( _balance3, SIGNAL( select() ), this, SLOT( slot_simple_select() ) ); + connect( _balance3, SIGNAL( replace() ), this, SLOT( slot_simple_replace() ) ); + + _volume_widget = new JackMix::GUI::Slider( amptodb( _volume_value ), dbmin, dbmax, 1, 3, this ); + _layout->addWidget( _volume_widget, 1,0,2,3 ); + _layout->setRowStretch( 1, 255 ); + connect( _volume_widget, SIGNAL( valueChanged( double ) ), this, SLOT( volume( double ) ) ); + connect( _volume_widget, SIGNAL( select() ), this, SLOT( slot_simple_select() ) ); + connect( _volume_widget, SIGNAL( replace() ), this, SLOT( slot_simple_replace() ) ); + + QAction *toggle = new QAction( "Toggle Selection", this ); + connect( toggle, SIGNAL( triggered() ), this, SLOT( slot_simple_select() ) ); + menu()->addAction( toggle ); + + QAction *replace = new QAction( "&Replace", this ); + connect( replace, SIGNAL( triggered() ), this, SLOT( slot_simple_replace() ) ); + menu()->addAction( replace ); + + QAction *explode = new QAction( "&Explode", this ); + explode->setShortcut(Qt::CTRL+Qt::Key_E); + this->addAction(explode); + connect( explode, SIGNAL( triggered() ), this, SLOT( slot_simple_explode() ) ); + menu()->addAction( explode ); + + QAction *assign = new QAction( "&Assign MIDI Parameter", this ); + connect( assign, SIGNAL( triggered() ), this, SLOT( slot_assign_midi_parameters() ) ); + menu()->addAction( assign ); + + + midi_params.append(0); + midi_delegates.append(_volume_widget); + midi_params.append(0); + midi_delegates.append(_balance3); + midi_delegates.append(_balance2); + midi_delegates.append(_balance); + + + + + + // Now construct the parameter setting menu + _cca = new JackMix::GUI::MidiControlChannelAssigner(QString("Set MIDI control parameter"), + "(" + _in[0] + "/" + _in[1] + "/" + _in[2] + + ") → (" + _out[0] + "/" + _out[1] + ")", + QStringList() << "Gain" << "Pan", + midi_params, + this + ); + connect( _cca, SIGNAL(assignParameters(QList)), this, SLOT(update_midi_parameters(QList)) ); + +} +Threeinput2outputElement::~Threeinput2outputElement() { +} + +void Threeinput2outputElement::balance( double n ) { + + _balance_value = n; + calculateVolumes(); + _balance->value( n ); + emit valueChanged( this, QString( "balance" ) ); +} +void Threeinput2outputElement::volume( double n ) { + + _volume_value = n; + calculateVolumes(); + _volume_widget->value( n ); + emit valueChanged( this, QString( "volume" ) ); +} + +void Threeinput2outputElement::calculateVolumes() { + double left, right; + left = dbtoamp( _volume_value ); + right = dbtoamp( _volume_value ); + if ( _balance_value > 0 ) + left = dbtoamp( _volume_value )*( 1-_balance_value ); + if ( _balance_value < 0 ) + right = dbtoamp( _volume_value )*( 1+_balance_value ); + backend()->setVolume( _in[0], _out[0], left ); + backend()->setVolume( _in[0], _out[1], right ); +} +void Threeinput2outputElement::balance2( double n ) { + + _balance_value2 = n; + calculateVolumes2(); + _balance2->value( n ); + emit valueChanged( this, QString( "balance2" ) ); +} + +void Threeinput2outputElement::calculateVolumes2() { + double left2, right2; + left2 = dbtoamp( _volume_value2 ); + right2 = dbtoamp( _volume_value2 ); + if ( _balance_value2 > 0 ) + left2 = dbtoamp( _volume_value2 )*( 1-_balance_value2 ); + if ( _balance_value2 < 0 ) + right2 = dbtoamp( _volume_value2 )*( 1+_balance_value2 ); + backend()->setVolume( _in[1], _out[0], left2 ); + backend()->setVolume( _in[1], _out[1], right2 ); +} + +void Threeinput2outputElement::balance3( double n ) { + + _balance_value3 = n; + calculateVolumes(); + _balance3->value( n ); + emit valueChanged( this, QString( "balance3" ) ); +} + +void Threeinput2outputElement::calculateVolumes3() { + double left3, right3; + left3 = dbtoamp( _volume_value3 ); + right3 = dbtoamp( _volume_value3 ); + if ( _balance_value3 > 0 ) + left3 = dbtoamp( _volume_value3 )*( 1-_balance_value3 ); + if ( _balance_value < 0 ) + right3 = dbtoamp( _volume_value3 )*( 1+_balance_value3 ); + backend()->setVolume( _in[2], _out[0], left3 ); + backend()->setVolume( _in[2], _out[1], right3 ); +} diff --git a/libelements/stereo_elements.h b/libelements/stereo_elements.h index ba30e28..798e48c 100644 --- a/libelements/stereo_elements.h +++ b/libelements/stereo_elements.h @@ -40,7 +40,7 @@ namespace MixerElements { class Mono2StereoElement; class Stereo2StereoElement; - +class Mono2StereoElement2; /** * A MonotoStereo control. */ @@ -101,6 +101,59 @@ private slots: JackMix::GUI::Slider *_volume_widget, *_balance_widget; }; + +class Mono2StereoElement2 : public JackMix::MixingMatrix::Element , public dB2VolCalc +{ +Q_OBJECT +Q_PROPERTY( double volume READ volume WRITE volume ); +Q_PROPERTY( double panorama READ panorama WRITE set_panorama ); +//Q_PROPERTY( double volume2 READ volume2 WRITE volume2 ); +Q_PROPERTY( double panorama2 READ panorama2 WRITE set_panorama2 ); +//Q_PROPERTY( double volume3 READ volume3 WRITE volume3 ); +Q_PROPERTY( double panorama3 READ panorama3 WRITE set_panorama3 ); +public: + Mono2StereoElement2( QStringList, QStringList, MixingMatrix::Widget*, const char* =0 ); + ~Mono2StereoElement2(); + + int inchannels() const { return 3; } + int outchannels() const { return 2; } + + + double volume() const { return _volume_value; } + double panorama() const { return _balance_value; } + //double volume2() const { return _volume_value2; } + double panorama2() const { return _balance_value2; } + //double volume3() const { return _volume_value3; } + double panorama3() const { return _balance_value3; } + +signals: + void volume_changed( double ); + void panorama_changed( double ); + void volume_changed2( double ); + void panorama_changed2( double ); + void volume_changed3( double ); + void panorama_changed3( double ); +public slots: + void set_panorama( double n ) { balance( n ); } + void balance( double ); + void volume( double ); + void set_panorama2( double n ) { balance2( n ); } + void balance2( double ); + //void volume2( double ); + void set_panorama3( double n ) { balance3( n ); } + void balance3( double ); + //void volume3( double ); +private slots: + void calculateVolumes(); + void calculateVolumes2(); + void calculateVolumes3(); +private: + QString _inchannel1, _inchannel2, _inchannel3, _outchannel1, _outchannel2; + JackMix::GUI::Knob *_balance, *_balance2, *_balance3; + JackMix::GUI::Slider *_volume_widget; + double _balance_value, _volume_value, _balance_value2, _volume_value2, _balance_value3, _volume_value3; +}; + void init_stereo_elements(); }; // MixerElements diff --git a/libgui/knob.cpp b/libgui/knob.cpp index c72f9e2..ca6b08b 100644 --- a/libgui/knob.cpp +++ b/libgui/knob.cpp @@ -109,16 +109,21 @@ void Knob::paintEvent( QPaintEvent* ) { p.setPen( Qt::NoPen ); { QRadialGradient grad( QPointF( 0,0 ), radius, QPointF( 0, radius*0.7 ) ); - grad.setColorAt( 0, _indicator ); - grad.setColorAt( 1, _indicator.darker() ); + //grad.setColorAt( 0, _indicator ); + //grad.setColorAt( 1, _indicator.darker() ); + grad.setColorAt( 0, Qt::darkGray ); + //grad.setColorAt( 1, Qt::black ); + grad.setSpread( QGradient::PadSpread ); p.setBrush( grad ); p.drawEllipse( QRectF( -radius*0.8, -radius*0.8, radius*1.6, radius*1.6 ) ); } { QRadialGradient grad( QPointF( 0,0 ), radius*0.60, QPointF( 0, radius*0.20 ) ); - grad.setColorAt( 1, palette().color( QPalette::Highlight ) ); - grad.setColorAt( 0, palette().color( QPalette::Highlight ).lighter() ); + //grad.setColorAt( 1, palette().color( QPalette::Light ) ); + //grad.setColorAt( 0, palette().color( QPalette::Light ).lighter() ); + grad.setColorAt( 1, Qt::black ); + grad.setColorAt( 0, Qt::gray ); grad.setSpread( QGradient::PadSpread ); p.setBrush( grad ); p.drawEllipse( QRectF( -radius*0.65, -radius*0.65, radius*1.3, radius*1.3 ) ); diff --git a/libgui/midicontrolchannelassigner.cpp b/libgui/midicontrolchannelassigner.cpp index 35380ca..9cec5db 100644 --- a/libgui/midicontrolchannelassigner.cpp +++ b/libgui/midicontrolchannelassigner.cpp @@ -101,8 +101,10 @@ void MidiControlChannelAssigner::commitnquit() { void MidiControlChannelAssigner::updateParameters(QList p) { // The MIDI parameters of the parent widget might have changed since construction + qDebug() << "p.size() is :" << p.size(); if (p.size() != _num_controls) qDebug() << "Update of MIDI dialogue data from wrong-size vector!"; + for (int i = 0; i < _num_controls; i++ ) { int ival; diff --git a/libmatrix/mixingmatrix.cpp b/libmatrix/mixingmatrix.cpp index fc4722e..444f035 100644 --- a/libmatrix/mixingmatrix.cpp +++ b/libmatrix/mixingmatrix.cpp @@ -43,6 +43,10 @@ #include #include +#include +#include +#include + namespace JackMix { namespace MixingMatrix { @@ -81,30 +85,34 @@ void Widget::addElement( Element* n ) { connect( n, SIGNAL( explode( Element* ) ), this, SLOT( explode( Element* ) ) ); resizeEvent( 0 ); } + void Widget::removeElement( Element* n ) { //qDebug("Removing element"); _elements.removeAll( n ); } void Widget::replace( Element* n ) { - //qDebug( "Widget::replace( Element* %p )", n ); - //qDebug( "This Element has %i selected neighbors.", n->neighbors() ); - //qDebug( " and %i selected followers.", n->followers( n->neighbors() ) ); + qDebug( "Widget::replace --- ( Element* %p )", n ); + qDebug( "Widget::replace --- This Element has %i selected neighbors.", n->neighbors() ); + qDebug( "Widget::replace --- and %i selected followers.", n->followers( n->neighbors() ) ); QStringList in, out; in = n->neighborsList(); - //qDebug( "Selected ins = %s", qPrintable( in.join( "," ) ) ); + qDebug( "Widget::replace --- Selected ins = %s", qPrintable( in.join( "," ) ) ); out = n->followersList(); - //qDebug( "Selected outs = %s", qPrintable( out.join( "," ) ) ); + qDebug( "Widget::replace --- Selected outs = %s", qPrintable( out.join( "," ) ) ); for ( QStringList::ConstIterator it=out.begin(); it!=out.end(); ++it ) { for ( QStringList::ConstIterator jt=in.begin(); jt!=in.end(); ++jt ) { Element* tmp = getResponsible( ( *jt ),( *it ) ); - //qDebug( "About to delete %p", tmp ); + qDebug( "Widget::replace --- About to delete %p", tmp ); if ( tmp ) tmp->deleteLater(); } } + createControl( in, out ); + QTimer::singleShot( 1, this, SLOT( autoFill() ) ); + } void Widget::explode( Element* n ) { @@ -126,6 +134,7 @@ bool Widget::createControl( QStringList inchannels, QStringList outchannels ) { //qDebug( "Widget::createControl( QStringList '%s', QStringList '%s', %s)", qPrintable( inchannels.join( "," ) ), qPrintable( outchannels.join( "," ) ) ); QStringList controls = Global::the()->canCreate( inchannels.size(), outchannels.size() ); + //QStringList controls = Global::the()->canCreate( 1, 2 ); if ( ! controls.isEmpty() ) { //qDebug( "Found %s to control [%i,%i] channels", controls.front().toStdString().c_str(), inchannels.size(), outchannels.size() ); return Global::the()->create( controls.front(), inchannels, outchannels, this ); @@ -141,10 +150,10 @@ void Widget::autoFill() { //qDebug( "Doing the Autofill-boogie..." ); for ( QStringList::Iterator init=_inchannels.begin(); init!=_inchannels.end(); ++init ) for ( QStringList::Iterator outit=_outchannels.begin(); outit!=_outchannels.end(); ++outit ) { - if ( !getResponsible( *init, *outit ) ) // { + if ( !getResponsible( *init, *outit ) ) { //qDebug( "...together with (%s|%s)", qPrintable( *init ), qPrintable( *outit ) ); createControl( QStringList()<<*init, QStringList()<<*outit ); - // } + } //else //qDebug( " (%s|%s) is allready occupied. :(", qPrintable( *init ), qPrintable( *outit ) ); } @@ -163,7 +172,6 @@ void Widget::autoFill() { //qDebug() << " No responsible element found, creating a new one"; createControl( QStringList()<<*init, QStringList()<<*init ); } - } } resizeEvent( 0 ); @@ -263,12 +271,35 @@ QSize Widget::smallestElement() const { return QSize( w,h ); } -QString Widget::nextIn( QString n ) const { + +QString Widget::previousIn( QString n) const { //qDebug() << "Widget::nextIn(" << n << ")"; if ( n.isNull() ) return 0; - int i = _inchannels.indexOf( n ) + 1; + int i = _inchannels.indexOf( n ) - 1; //qDebug() << " i=" << i; + if ( i > -1) + return _inchannels.at( i ); + return 0; +} + +QString Widget::previousOut( QString n ) const { + if ( n.isNull() ) + return 0; + int i = _outchannels.indexOf( n ) - 1; + if ( i > -1 ) + return _outchannels.at( i ); + return 0; +} + + + +QString Widget::nextIn( QString n ) const { + qDebug() << "Widget::nextIn --- (" << n << ")"; + if ( n.isNull() ) + return 0; + int i = _inchannels.indexOf( n ) + 1; + qDebug() << "Widget::nextIn --- i=" << i; if ( i < _inchannels.size() ) return _inchannels.at( i ); return 0; @@ -394,6 +425,8 @@ bool Element::isResponsible( QString in, QString out ) { return false; } + + void Element::select( bool n ) { //qDebug( "MixingMatrix::Element::select( bool %i )", n ); if ( n != _selected ) { @@ -401,6 +434,7 @@ void Element::select( bool n ) { _selected = n; QPalette pal; if ( _selected ) { + //connect(pCheckbox, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(onButtonClicked(QAbstractButton*))); setFrameShadow( QFrame::Sunken ); pal.setColor( QPalette::Window, pal.color( QPalette::Window ).darker() ); } else { @@ -415,22 +449,48 @@ void Element::select( bool n ) { } } + + int Element::neighbors() const { - Element* neighbor = _parent->getResponsible( _parent->nextIn( _in[ _in.size()-1 ] ), _out[ 0 ] ); - if ( neighbor && neighbor->isSelected() ) - return neighbor->neighbors()+1; + Element* neighbor_r = _parent->getResponsible( _parent->nextIn( _in[ _in.size()-1 ] ), _out[ 0 ] ); + //Element* neighbor_l = _parent->getResponsible( _parent->previousIn( _in[ _in.size()-1 ] ), _out[ 0 ] ); + if ( neighbor_r && neighbor_r->isSelected() ) + return neighbor_r->neighbors()+1; + //if ( neighbor_l && neighbor_l->isSelected() ) + // return neighbor_l->neighbors()-1; return 0; } + QStringList Element::neighborsList() const { - //qDebug( "self = [%s]", qPrintable( _in.join( "|" ) ) ); - //qDebug( "neighbor = %s", qPrintable( _parent->nextIn( _in[ _in.size()-1 ] ) ) ); - Element* neighbor = _parent->getResponsible( _parent->nextIn( _in[ _in.size()-1 ] ), _out[ 0 ] ); + qDebug( "Element::neighborList --- self = [%s]", qPrintable( _in.join( "|" ) ) ); + qDebug( "Element::neighborList --- neighbor_r = %s", qPrintable( _parent->nextIn( _in[ _in.size()-1 ] ) ) ); + //qDebug( "neighbor_l = %s", qPrintable( _parent->previousIn( _in[ _in.size()-1 ] ) ) ); + Element* neighbor_r = _parent->getResponsible( _parent->nextIn( _in[ _in.size()-1 ] ), _out[ 0 ] ); + //Element* neighbor_l = _parent->getResponsible( _parent->previousIn( _in[ _in.size()-1 ] ), _out[ 0 ] ); QStringList tmp; - if ( neighbor && neighbor->isSelected() ) - tmp = neighbor->neighborsList(); + //QString neighbor = qPrintable( _parent->nextIn( _in[ _in.size()-1 ] ) ); + //if ( neighbor_l && neighbor_l->isSelected()) { + // tmp = neighbor_l->neighborsList(); + // tmp = tmp + _in; + //} + //qDebug( "Element::neighborList --- _in is %s", qPrintable(_in.join(","))); + + if (neighbor_r && neighbor_r->isSelected()) + tmp = neighbor_r->neighborsList(); tmp = _in + tmp; + + qDebug( "Element::neighborList --- tmp is %s", qPrintable(tmp.join(","))); + qDebug( "Element::neighborList --- _in is %s", qPrintable(_in.join(","))); + return tmp; + //if ( neighbor_l && neighbor_l->isSelected() ) + //tmp = neighbor_l->neighborsList(); + + //return _in; } + + + int Element::followers( int n ) const { if ( n==0 ) return 0; @@ -446,7 +506,7 @@ QStringList Element::followersList() const { QStringList tmp; if ( follower && follower->isSelected() ) tmp = follower->followersList(); - tmp = _out + tmp; + tmp = _out + tmp; return tmp; } @@ -497,6 +557,8 @@ void Element::renamechannels(QString old_name, QString new_name) if (disp_name) disp_name->setText( QString("
%1
").arg(new_name) ); } + + ElementFactory::ElementFactory() { Global::the()->registerFactory( this ); } @@ -517,20 +579,20 @@ Global* Global::the() { } void Global::registerFactory( ElementFactory* n ) { - //qDebug( "Global::registerFactory( ElementFactory* %p )", n ); + qDebug( "Global::registerFactory( ElementFactory* %p )", n ); _factories.push_back( n ); } void Global::unregisterFactory( ElementFactory* n ) { - //qDebug( "Global::unregisterFactory( ElementFactory* %p )", n ); + qDebug( "Global::unregisterFactory( ElementFactory* %p )", n ); _factories.removeAll( n ); } QStringList Global::canCreate( int in, int out ) { - //qDebug() << "Global::canCreate(" << in << "," << out << ")"; + qDebug() << "Global::canCreate(" << in << "," << out << ")"; QStringList tmp; for ( int i=0; i<_factories.size(); i++ ) tmp += _factories[ i ]->canCreate( in, out ); - //qDebug() << " returning" << tmp; + qDebug() << " returning" << tmp; return tmp; } diff --git a/libmatrix/mixingmatrix.h b/libmatrix/mixingmatrix.h index 365d73d..400891e 100644 --- a/libmatrix/mixingmatrix.h +++ b/libmatrix/mixingmatrix.h @@ -68,6 +68,8 @@ Q_PROPERTY( Direction direction READ direction WRITE direction ) QStringList inchannels() const { return _inchannels; } QStringList outchannels() const { return _outchannels; } + QString previousIn( QString ) const; + QString previousOut( QString ) const; QString nextIn( QString ) const; QString nextOut( QString ) const; @@ -201,6 +203,7 @@ Q_PROPERTY( QString name READ name WRITE name ) /** Allow others to see our controlling midi parameters (but not change them) */ const QList& midiParameters() const; + /** Inform the Element the parent's dead so it doesn't try to deregister itself * on destruction (otherwise there may be a segfault at closedown) */