drumstick 0.5.0
vpiano.cpp

A Virtual Piano Keyboard GUI application.

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
Classes managing ALSA Sequencer clients.
Classes managing ALSA Sequencer events.
Classes managing ALSA Sequencer ports.
Classes managing ALSA Sequencer queues.
The QEvent class is the base class of all event classes.
Client management.
Definition: alsaclient.h:199
Port management.
Definition: alsaport.h:120
Base class for the event's hierarchy.
Definition: alsaevent.h:54
Subscription management.
Definition: subscription.h:83
/*
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());
}
}
}