drumstick 0.5.0
|
A Virtual Piano Keyboard GUI application. See another one at http://vmpk.sf.net
/* Virtual Piano test using the MIDI Sequencer C++ library Copyright (C) 2006-2010, Pedro Lopez-Cabanillas <plcl@users.sf.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef VPIANO_H #define VPIANO_H #include <QMainWindow> #include "ui_vpiano.h" #include "vpianoabout.h" #include "connections.h" #include "preferences.h" #include "alsaevent.h" #include "alsaclient.h" #include "alsaport.h" #include "alsaqueue.h" using namespace drumstick; /* MidiClient can deliver SequencerEvents with only * signals or posting QEvents to the QApplication loop */ #undef USE_QEVENTS //#define USE_QEVENTS class VPiano : public QMainWindow { Q_OBJECT public: VPiano( QWidget * parent = 0, Qt::WindowFlags flags = 0 ); virtual ~VPiano(); public slots: void slotAbout(); void slotAboutQt(); void slotConnections(); void slotPreferences(); void slotNoteOn(const int midiNote); void slotNoteOff(const int midiNote); void slotSubscription(MidiPort* port, Subscription* subs); #ifdef USE_QEVENTS protected: virtual void customEvent( QEvent *ev ); #else void sequencerEvent( SequencerEvent* ev ); #endif private: void displayEvent( SequencerEvent* ev ); int m_portId; MidiClient* m_Client; MidiPort* m_Port; Ui::VPiano ui; About dlgAbout; Connections dlgConnections; Preferences dlgPreferences; }; #endif // VPIANO_H
/* Virtual Piano test using the MIDI Sequencer C++ library Copyright (C) 2006-2010, Pedro Lopez-Cabanillas <plcl@users.sf.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <QDebug> #include "vpiano.h" VPiano::VPiano( QWidget * parent, Qt::WindowFlags flags ) : QMainWindow(parent, flags), m_portId(-1), m_Client(0), m_Port(0) { ui.setupUi(this); ui.statusBar->hide(); ui.pianokeybd->setRawKeyboardMode(true); m_Client = new MidiClient(this); m_Client->open(); m_Client->setClientName("Virtual Piano"); #ifdef USE_QEVENTS m_Client->addListener(this); m_Client->setEventsEnabled(true); #else // USE_QEVENTS (using signals instead) connect( m_Client, SIGNAL(eventReceived(SequencerEvent*)), SLOT(sequencerEvent(SequencerEvent*)), Qt::QueuedConnection ); #endif // USE_QEVENTS m_Port = new MidiPort(this); m_Port->attach( m_Client ); m_Port->setPortName("Virtual Piano"); m_Port->setCapability( SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE ); m_Port->setPortType( SND_SEQ_PORT_TYPE_APPLICATION ); m_portId = m_Port->getPortId(); connect(ui.actionExit, SIGNAL(triggered()), qApp, SLOT(quit())); connect(ui.actionAbout, SIGNAL(triggered()), SLOT(slotAbout())); connect(ui.actionAbout_Qt, SIGNAL(triggered()), SLOT(slotAboutQt())); connect(ui.actionConnections, SIGNAL(triggered()), SLOT(slotConnections())); connect(ui.actionPreferences, SIGNAL(triggered()), SLOT(slotPreferences())); connect(ui.pianokeybd, SIGNAL(noteOn(int)), SLOT(slotNoteOn(int))); connect(ui.pianokeybd, SIGNAL(noteOff(int)), SLOT(slotNoteOff(int))); connect(m_Port, SIGNAL(subscribed(MidiPort*,Subscription*)), SLOT(slotSubscription(MidiPort*,Subscription*))); m_Port->subscribeFromAnnounce(); m_Client->setRealTimeInput(false); m_Client->startSequencerInput(); } VPiano::~VPiano() { m_Client->stopSequencerInput(); m_Port->detach(); m_Client->close(); qDebug() << "Cheers!"; } void VPiano::slotNoteOn(const int midiNote) { int chan = dlgPreferences.getOutChannel(); int vel = dlgPreferences.getVelocity(); NoteOnEvent ev(chan, midiNote, vel); ev.setSource(m_portId); ev.setSubscribers(); ev.setDirect(); m_Client->outputDirect(&ev); } void VPiano::slotNoteOff(const int midiNote) { int chan = dlgPreferences.getOutChannel(); int vel = dlgPreferences.getVelocity(); NoteOffEvent ev(chan, midiNote, vel); ev.setSource(m_portId); ev.setSubscribers(); ev.setDirect(); m_Client->outputDirect(&ev); } void VPiano::displayEvent(SequencerEvent *ev) { try { switch (ev->getSequencerType()) { case SND_SEQ_EVENT_NOTEON: { NoteOnEvent* e = static_cast<NoteOnEvent*>(ev); if ((e != NULL) && (dlgPreferences.getInChannel() == e->getChannel())) { int note = e->getKey(); if (e->getVelocity() == 0) ui.pianokeybd->showNoteOff(note); else ui.pianokeybd->showNoteOn(note); //qDebug() << "NoteOn" << note; } break; } case SND_SEQ_EVENT_NOTEOFF: { NoteOffEvent* e = static_cast<NoteOffEvent*>(ev); if ((e != NULL) && (dlgPreferences.getInChannel() == e->getChannel())) { int note = e->getKey(); ui.pianokeybd->showNoteOff(note); //qDebug() << "NoteOff" << note; } break; } default: break; } } catch (SequencerError& err) { qWarning() << "SequencerError exception. Error code: " << err.code() << " (" << err.qstrError() << ")"; qWarning() << "Location: " << err.location(); throw err; } } #ifdef USE_QEVENTS void VPiano::customEvent(QEvent *ev) { if ( (ev == 0) || (ev->type() != SequencerEventType) ) return; SequencerEvent* sev = static_cast<SequencerEvent*>(ev); displayEvent (sev); } #else void VPiano::sequencerEvent(SequencerEvent *ev) { displayEvent (ev); delete ev; } #endif void VPiano::slotSubscription(MidiPort*, Subscription* subs) { qDebug() << "Subscription made with" << subs->getSender()->client << ":" << subs->getSender()->port; } void VPiano::slotAbout() { dlgAbout.exec(); } void VPiano::slotAboutQt() { qApp->aboutQt(); } void VPiano::slotConnections() { m_Port->updateSubscribers(); dlgConnections.setInputs(m_Client->getAvailableInputs(), m_Port->getWriteSubscribers()); dlgConnections.setOutputs(m_Client->getAvailableOutputs(), m_Port->getReadSubscribers()); if (dlgConnections.exec() == QDialog::Accepted) { m_Port->updateConnectionsFrom(dlgConnections.getSelectedInputPorts()); m_Port->updateConnectionsTo(dlgConnections.getSelectedOutputPorts()); } } void VPiano::slotPreferences() { if (dlgPreferences.exec() == QDialog::Accepted) { if (ui.pianokeybd->baseOctave() != dlgPreferences.getBaseOctave()) { ui.pianokeybd->setBaseOctave(dlgPreferences.getBaseOctave()); } if (ui.pianokeybd->numOctaves() != dlgPreferences.getNumOctaves()) { ui.pianokeybd->setNumOctaves(dlgPreferences.getNumOctaves()); } } }