drumstick  0.5.0
vpiano.cpp

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());
}
}
}