drumstick  1.1.3
drumstick Documentation
Author
Copyright © 2009-2017 Pedro López-Cabanillas <plcl AT users.sf.net>
Date
2017-08-15
Version
1.1.1

This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/

Abstract

This is the reference documentation for drumstick. These libraries are a set of C++ MIDI related classes, using Qt5 objects, idioms and style.

Currently, there are three libraries:

  • drumstick-alsa is a C++/Qt wrapper around the ALSA Sequencer API. ALSA sequencer provides software support for MIDI technology on Linux.
  • drumstick-file provides easy multiplatform file I/O for Standard MIDI Files (.mid), Cakewalk (.wrk) and Overture (.ove) file formats.
  • drumstick-rt is a realtime MIDI I/O library with pluggable backends. It uses drumstick-alsa on Linux, and other frameworks on Mac and Windows.
See also
http://qt-project.org/doc/qt-5/index.html
http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html
http://www.ics.com/design-patterns
http://www.midi.org/articles/tutorials

Disclaimer

This document is a work in progress, in a very early state. It will be always in development. Please visit the drumstick web site to read the latest version.

See also
http://drumstick.sourceforge.net

Introduction

For an introduction to design and programming with C++ and Qt, see the book "An Introduction to Design Patterns in C++ with Qt" by by Alan Ezust and Paul Ezust. It is available published on dead trees, and also online.

Here is how a simple program playing notes using drumstick-alsa looks like:

#include <QApplication>
#include <drumstick.h>
int main(int argc, char **argv) {
QApplication app(argc, argv, false);
// create a client object on the heap
client->open();
client->setClientName( "MyClient" );
// create the port. Pointer is owned by the client instance
drumstick::MidiPort *port = client->createPort();
port->setPortName( "MyPort" );
port->setCapability( SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ );
port->setPortType( SND_SEQ_PORT_TYPE_MIDI_GENERIC );
// subscribe the port to some other client:port
port->subscribeTo( "128:0" ); // or "name:port", like in "FluidSynth:0"
QList<int> notes = { 60, 62, 64, 65, 67, 69, 71, 72 };
for(int i = 0; i < notes.length(); ++i)
{
// create event objects on the stack, to send note on/off messages
drumstick::NoteOnEvent ev1( 0, notes[i], 100 ); // (channel, note number, velocity)
ev1.setSource( port->getPortId() );
ev1.setSubscribers(); // deliver to all the connected ports
ev1.setDirect(); // not scheduled, deliver immediately
client->output( &ev1 ); // or outputDirect() if you prefer not buffered
client->drainOutput(); // flush the buffer
QThread::msleep(250); // wait a quarter second
drumstick::NoteOffEvent ev2( 0, notes[i], 0 ); // (channel, note number, velocity)
ev2.setSource( port->getPortId() );
ev2.setSubscribers(); // deliver to all the connected ports
ev2.setDirect(); // not scheduled, deliver immediately
client->output( &ev2 ); // or outputDirect() if you prefer not buffered
client->drainOutput(); // flush the buffer
}
// close and clean
client->close();
delete client;
return 0;
}

A similar example can also be implemented using the drumstick-rt library:

#include <QApplication>
#include <drumstick.h>
int main(int argc, char **argv) {
QApplication app(argc, argv, false);
if (output != 0) {
qDebug() << "testing backend: " << output->backendName();
qDebug() << "public name " << output->publicName();
foreach(const QString& c, output->connections()) {
qDebug() << "port " << c;
}
output->open("FLUID Synth (qsynth):0");
QList<int> notes = { 60, 62, 64, 65, 67, 69, 71, 72 };
for(int i = 0; i < notes.length(); ++i)
{
output->sendNoteOn(0, notes[i], 100);
QThread::msleep(250); // wait a quarter second
output->sendNoteOff(0, notes[i], 0);
}
output->close();
}
return 0;
}

A common pattern on both implementations is QThread::msleep(250) to do the rhythm. If you are targeting only Linux, you may be interested on another (better) way to do the same, using drumstick-alsa again, because ALSA Sequencer is capable of event sacheduling (that is why it is called a Sequencer).

#include <QApplication>
#include <drumstick.h>
int main(int argc, char **argv) {
QApplication app(argc, argv, false);
client->open();
client->setClientName( "MyClient" );
drumstick::MidiPort *port = client->createPort();
port->setPortName( "MyPort" );
port->setCapability( SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ );
port->setPortType( SND_SEQ_PORT_TYPE_MIDI_GENERIC );
port->subscribeTo( "FLUID Synth (qsynth):0" );
drumstick::MidiQueue *queue = client->createQueue( "MyQueue" );
drumstick::QueueTempo tempo = queue->getTempo();
tempo.setNominalBPM( 120 );
queue->setTempo(tempo);
client->drainOutput();
queue->start();
int tick = 0;
QList<int> notes = { 60, 62, 64, 65, 67, 69, 71, 72 };
for(int i = 0; i < notes.length(); ++i)
{
drumstick::NoteOnEvent ev1( 0, notes[i], 100 );
ev1.setSource( port->getPortId() );
ev1.setSubscribers();
ev1.scheduleTick(queue->getId(), tick, false);
client->output( &ev1 );
tick += 60;
drumstick::NoteOffEvent ev2( 0, notes[i], 0 );
ev2.setSource( port->getPortId() );
ev2.setSubscribers();
ev2.scheduleTick(queue->getId(), tick, false);
client->output( &ev2 );
}
client->drainOutput();
client->synchronizeOutput();
queue->stop();
// close and clean
client->close();
delete client;
return 0;
}

There are more examples in the source tree, under the utils/ directory, and you can also see applications using this library, like kmetronome, kmidimon and VMPK.

See also
http://kmetronome.sourceforge.net
http://kmidimon.sourceforge.net
http://kmid2.sourceforge.net
http://vmpk.sourceforge.net

Acknowledgments

Parts of this documentation are copied from the ALSA library documentation, whose authors are:

  • Jaroslav Kysela <perex AT perex.cz>
  • Abramo Bagnara <abramo AT alsa-project.org>
  • Takashi Iwai <tiwai AT suse.de>
  • Frank van de Pol <fvdpol AT coil.demon.nl>
drumstick::MidiClient::output
void output(SequencerEvent *ev, bool async=false, int timeout=-1)
Output an event using the library output buffer.
Definition: alsaclient.cpp:988
drumstick::MidiClient::synchronizeOutput
void synchronizeOutput()
Wait until all sent events are processed.
Definition: alsaclient.cpp:1081
drumstick::rt::MIDIOutput
MIDI OUT interface.
Definition: rtmidioutput.h:80
drumstick::rt::MIDIOutput::sendNoteOff
virtual void sendNoteOff(int chan, int note, int vel)=0
sendNoteOff 0x8
drumstick::MidiClient::open
void open(const QString deviceName="default", const int openMode=SND_SEQ_OPEN_DUPLEX, const bool blockMode=false)
Open the sequencer device.
Definition: alsaclient.cpp:388
drumstick::rt::BackendManager::outputBackendByName
MIDIOutput * outputBackendByName(const QString name)
outputBackendByName
Definition: backendmanager.cpp:260
drumstick::MidiClient::createQueue
MidiQueue * createQueue()
Create and return a new MidiQueue associated to this client.
Definition: alsaclient.cpp:1105
drumstick::MidiPort::setPortName
void setPortName(QString const &newName)
Sets the port name.
Definition: alsaport.cpp:903
drumstick::MidiClient::close
void close()
Close the sequencer device.
Definition: alsaclient.cpp:445
drumstick::MidiQueue::setTempo
void setTempo(const QueueTempo &value)
Applies a QueueTempo object to the queue.
Definition: alsaqueue.cpp:805
drumstick::MidiClient::createPort
MidiPort * createPort()
Create and attach a new MidiPort instance to this client.
Definition: alsaclient.cpp:858
drumstick::rt::BackendManager
The BackendManager class manages lists of dynamic and static backends for applications based on drums...
Definition: backendmanager.h:49
drumstick::MidiPort::setPortType
void setPortType(unsigned int newValue)
Sets the port type bitmap.
Definition: alsaport.cpp:959
drumstick::rt::MIDIOutput::open
virtual void open(QString name)=0
open the MIDI port by name
drumstick::MidiQueue::stop
void stop()
Stop the queue.
Definition: alsaqueue.cpp:857
drumstick::QueueTempo
Queue tempo container.
Definition: alsaqueue.h:116
drumstick::QueueTempo::setNominalBPM
void setNominalBPM(float value)
Sets the queue's nominal tempo in BPM (beats per minute).
Definition: alsaqueue.cpp:515
drumstick::rt::MIDIOutput::close
virtual void close()=0
close the MIDI port
drumstick::MidiClient
Client management.
Definition: alsaclient.h:197
drumstick::MidiPort::subscribeTo
void subscribeTo(PortInfo *port)
Subscribe to another port destination.
Definition: alsaport.cpp:654
drumstick::MidiClient::drainOutput
void drainOutput(bool async=false, int timeout=-1)
Drain the library output buffer.
Definition: alsaclient.cpp:1058
drumstick.h
drumstick::MidiClient::setClientName
void setClientName(QString const &newName)
Changes the public name of the ALSA sequencer client.
Definition: alsaclient.cpp:835
drumstick::rt::MIDIOutput::publicName
virtual QString publicName()=0
publicName
drumstick::MidiQueue::getTempo
QueueTempo & getTempo()
Gets a QueueTempo object reference.
Definition: alsaqueue.cpp:775
drumstick::MidiPort::getPortId
int getPortId()
Gets the port number.
Definition: alsaport.cpp:914
drumstick::rt::MIDIOutput::backendName
virtual QString backendName()=0
backendName
drumstick::MidiQueue
Queue management.
Definition: alsaqueue.h:187
drumstick::MidiPort
Port management.
Definition: alsaport.h:118
drumstick::NoteOnEvent
Event representing a note-on MIDI event.
Definition: alsaevent.h:237
drumstick::rt::MIDIOutput::connections
virtual QStringList connections(bool advanced=false)=0
connections
drumstick::rt::MIDIOutput::sendNoteOn
virtual void sendNoteOn(int chan, int note, int vel)=0
sendNoteOn 0x9
drumstick::NoteOffEvent
Event representing a note-off MIDI event.
Definition: alsaevent.h:252
drumstick::MidiQueue::start
void start()
Start the queue.
Definition: alsaqueue.cpp:846
drumstick::MidiPort::setCapability
void setCapability(unsigned int newValue)
Sets the port capabilities.
Definition: alsaport.cpp:936