Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 260 lines (230 sloc) 8.115 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qextserialport/qextserialenumerator.h"
#include "src/Settings.h"
#include "src/settingsdialog.h"
#include "src/aboutdialog.h"

const int LIST_REFRESH_RATE =20; // Hz

static void selectIfAvailable(QComboBox *box, QString itemText)
{
    for(int i = 0; i < box->count(); i++) {
        if(box->itemText(i) == itemText) {
            box->setCurrentIndex(i);
            return;
        }
    }
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    bridge(NULL),
    workerThread(NULL),
    debugListTimer(),
    debugListMessages()
{
    ui->setupUi(this);
    // Fixed width, minimum height
    this->setMinimumSize(this->size());
    this->setMaximumSize(this->size().width(), 2000);
#ifdef Q_OS_LINUX
    this->setWindowIcon(QIcon(":/images/images/icon48.png"));
#endif

    // Plumb event filter for focus events
    ui->cmbMidiIn->installEventFilter(this);
    ui->cmbMidiOut->installEventFilter(this);
    ui->cmbSerial->installEventFilter(this);

    // Load initial state
    this->workerThread = new QThread();
    this->workerThread->start(QThread::HighestPriority);
    refresh();
    scrollbackSize=Settings::getScrollbackSize();
    ui->chk_debug->setChecked( Settings::getDebug() );
    selectIfAvailable(ui->cmbMidiIn, Settings::getLastMidiIn());
    selectIfAvailable(ui->cmbMidiOut, Settings::getLastMidiOut());
    selectIfAvailable(ui->cmbSerial, Settings::getLastSerialPort());

    // Set up timer for the display list
    debugListTimer.setSingleShot(true);
    debugListTimer.setInterval(1000 / LIST_REFRESH_RATE);

    // Plumb signals & slots
    connect(ui->cmbMidiIn, SIGNAL(currentIndexChanged(int)), SLOT(onValueChanged()));
    connect(ui->cmbMidiOut, SIGNAL(currentIndexChanged(int)), SLOT(onValueChanged()));
    connect(ui->cmbSerial, SIGNAL(currentIndexChanged(int)), SLOT(onValueChanged()));
    connect(ui->chk_on, SIGNAL(clicked()), SLOT(onValueChanged()));
    connect(ui->chk_debug, SIGNAL(clicked(bool)), SLOT(onDebugClicked(bool)));
    connect(&debugListTimer, SIGNAL(timeout()), SLOT(refreshDebugList()));


    // Menu items
    connect(ui->actionExit, SIGNAL(triggered()), qApp, SLOT(quit()));
    connect(ui->actionAbout, SIGNAL(triggered()), SLOT(showAboutBox()));
    connect(ui->actionPreferences, SIGNAL(triggered()), SLOT(showPreferences()));

    // Get started
    onValueChanged();

#ifdef Q_OS_MAC
    // hack: avoid an empty dummy File menu on OS X
    // there might be a better way to do this, but hide() and clear() don't work.
    ui->menuFile->setTitle(""); // Doesn't do anything on OS X
#endif

}


MainWindow::~MainWindow()
{
    bridge->deleteLater();
    delete ui;
}

void MainWindow::showPreferences()
{
    SettingsDialog dialog;
    if(dialog.exec() == QDialog::Accepted) {
        scrollbackSize=Settings::getScrollbackSize();
        onValueChanged();
    }
}

void MainWindow::showAboutBox()
{
    AboutDialog().exec();
}

bool MainWindow::eventFilter(QObject *object, QEvent *event) {
    // If user is triggering a dropdown, refresh it live
    if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::KeyPress) {
        if(object == ui->cmbMidiIn) {
            RtMidiIn in;
            refreshMidi(ui->cmbMidiIn, &in);
        } else if (object == ui->cmbMidiOut) {
            RtMidiOut out;
            refreshMidi(ui->cmbMidiOut, &out);
        }
        else if (object == ui->cmbSerial) {
            refreshSerial();
        }
    }
    return false;
}

void MainWindow::refresh()
{
    refreshSerial();
    refreshMidiIn();
    refreshMidiOut();
}

void MainWindow::refreshMidiIn()
{
    RtMidiIn in = RtMidiIn();
    refreshMidi(ui->cmbMidiIn, &in);
}

void MainWindow::refreshMidiOut()
{
    RtMidiOut out = RtMidiOut();
    refreshMidi(ui->cmbMidiOut, &out);
}


void MainWindow::refreshMidi(QComboBox *combo, RtMidi *midi)
{
    QString current = combo->currentText();
    combo->clear();
    try
    {
      int ports = midi->getPortCount();
      combo->addItem(TEXT_NOT_CONNECTED);
      for (int i = 0; i < ports; i++ ) {
        QString name = QString::fromStdString(midi->getPortName(i));
        combo->addItem(name);
            if(current == name) {
                combo->setCurrentIndex(combo->count() - 1);
           }
        }
    }
    catch (RtError err) {
        ui->lst_debug->addItem("Failed to scan for MIDI ports:");
        ui->lst_debug->addItem(QString::fromStdString(err.getMessage()));
        ui->lst_debug->scrollToBottom();
    }
}

void MainWindow::refreshSerial()
{
    QString current = ui->cmbSerial->currentText();
    ui->cmbSerial->clear();
    ui->cmbSerial->addItem(TEXT_NOT_CONNECTED);
    QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();
    for(QList<QextPortInfo>::iterator it = ports.begin(); it != ports.end(); it++) {
#ifdef Q_OS_MAC
        QString label = it->portName; // OS X has no friendly name set
#else
        QString label = it->friendName;
#endif
#ifdef Q_OS_LINUX
        QString portName = it->physName; // Bug workaround, Linux needs the /dev/ in front of port name
#else
        QString portName = it->portName;
#endif

        ui->cmbSerial->addItem(label, QVariant(portName));
        if(current == it->friendName) {
            ui->cmbSerial->setCurrentIndex(ui->cmbSerial->count() - 1);
        }
    }
}

void MainWindow::onDebugClicked(bool value)
{
    Settings::setDebug(value);
}

void MainWindow::onValueChanged()
{
    if(bridge) {
        bridge->deleteLater();
        QThread::yieldCurrentThread(); // Try and get any signals from the bridge sent sooner not later
        QCoreApplication::processEvents();
        bridge = NULL;
    }
    Settings::setLastMidiIn(ui->cmbMidiIn->currentText());
    Settings::setLastMidiOut(ui->cmbMidiOut->currentText());
    Settings::setLastSerialPort(ui->cmbSerial->currentText());
    if(!ui->chk_on->isChecked()
            || ( ui->cmbSerial->currentIndex() == 0
                    && ui->cmbMidiIn->currentIndex() == 0
                    && ui->cmbMidiOut->currentIndex() == 0 )) {
        return;
    }
    ui->lst_debug->clear();
    int midiIn =ui->cmbMidiIn->currentIndex()-1;
    int midiOut = ui->cmbMidiOut->currentIndex()-1;
    ui->lst_debug->addItem("Starting MIDI<->Serial Bridge...");
    bridge = new Bridge();
    connect(bridge, SIGNAL(debugMessage(QString)), SLOT(onDebugMessage(QString)));
    connect(bridge, SIGNAL(displayMessage(QString)), SLOT(onDisplayMessage(QString)));
    connect(bridge, SIGNAL(midiReceived()), ui->led_midiin, SLOT(blinkOn()));
    connect(bridge, SIGNAL(midiSent()), ui->led_midiout, SLOT(blinkOn()));
    connect(bridge, SIGNAL(serialTraffic()), ui->led_serial, SLOT(blinkOn()));
    bridge->attach(ui->cmbSerial->itemData(ui->cmbSerial->currentIndex()).toString(), Settings::getPortSettings(), midiIn, midiOut, workerThread);
}

void MainWindow::onDisplayMessage(QString message)
{
    if(debugListMessages.size() == scrollbackSize)
        debugListMessages.removeFirst();
    debugListMessages.append(message);
    if(!debugListTimer.isActive())
        debugListTimer.start();
}

void MainWindow::onDebugMessage(QString message)
{
    if(ui->chk_debug->isChecked())
        onDisplayMessage(message);
}

/*
* When the timer (started in onDisplayMessage) fires, we update lst_debug with the
* contents of debugListMessages.
*
* This happens in the timer event in order to rate limit it to a number of redraws per second
* (redrawing, and especially scrolling the list view, can be quite resource intensive.)
*/
void MainWindow::refreshDebugList()
{
    QListWidget *lst = ui->lst_debug;
    while(lst->count() + debugListMessages.size() - scrollbackSize > 0 && lst->count() > 0) {
      delete lst->item(0);
    }
    lst->addItems(debugListMessages);
    debugListMessages.clear();
    lst->scrollToBottom();
}

void MainWindow::resizeEvent(QResizeEvent *)
{
    QListWidget *lst = ui->lst_debug;
    QRect geo = lst->geometry();
    geo.setHeight( this->height() - geo.top() - 20 );
    lst->setGeometry(geo);
}
Something went wrong with that request. Please try again.