drumstick  1.1.0
drumstick Documentation
Author
Copyright © 2009-2016 Pedro L√≥pez-Cabanillas <plcl AT users.sf.net>
Date
2016-08-21
Version
1.1.0

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>