- Author
- Copyright © 2009-2023 Pedro López-Cabanillas <plcl AT users.sf.net>
- Date
- December 23, 2023
- Version
- 2.9.0
This document is licensed under the Creative Commons Attribution-Share Alike 4.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/
Abstract
This is the reference documentation for drumstick. These libraries are a set of C++ MIDI related classes, using Qt objects, idioms and style.
Currently, there are four libraries designed to work together if/when needed:
- Drumstick::ALSA is a Linux only 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), RIFF MIDI (.rmi) and Cakewalk (.wrk) file formats.
- Drumstick::RT is a realtime MIDI I/O library with pluggable backends. It uses Drumstick::ALSA on Linux, and other native frameworks on macOS and Windows.
- Drumstick::Widgets contains MIDI widgets, including a Virtual Piano used by VMPK among other programs
- See also
- https://doc.qt.io/qt-5/index.html
-
https://www.alsa-project.org/alsa-doc/alsa-lib/seq.html
-
https://www.ics.com/intro-design-patterns-c-qt-2nd-edition
-
https://www.midi.org/articles/tutorials
Disclaimer
This document is a work in progress and it will be always in development. Please visit the drumstick web site to read the latest version.
- See also
- https://drumstick.sourceforge.io
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.
Drumstick::ALSA was the first library developed under the Drumstick umbrella, and is available only on Linux, because ALSA Sequencer is an exclusive Linux technology. Here is how a simple program playing notes using Drumstick::ALSA looks like:
#include <QCoreApplication>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
port->
setCapability( SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ );
QList<int> notelist{ 60, 62, 64, 65, 67, 69, 71, 72 };
for(auto note : notelist)
{
ev1.setSubscribers();
ev1.setDirect();
QThread::msleep(250);
ev2.setSubscribers();
ev2.setDirect();
}
delete client;
return 0;
}
Classes managing ALSA Sequencer clients.
Classes managing ALSA Sequencer events.
void subscribeTo(PortInfo *port)
Subscribe to another port destination.
void setPortName(QString const &newName)
Sets the port name.
void setPortType(unsigned int newValue)
Sets the port type bitmap.
void setCapability(unsigned int newValue)
Sets the port capabilities.
int getPortId()
Gets the port number.
Event representing a note-off MIDI event.
Event representing a note-on MIDI event.
void close()
Close the sequencer device.
void setClientName(QString const &newName)
Changes the public name of the ALSA sequencer client.
void output(SequencerEvent *ev, bool async=false, int timeout=-1)
Output an event using the library output buffer.
MidiPort * createPort()
Create and attach a new MidiPort instance to this client.
void open(const QString deviceName="default", const int openMode=SND_SEQ_OPEN_DUPLEX, const bool blockMode=false)
Open the sequencer device.
void drainOutput(bool async=false, int timeout=-1)
Drain the library output buffer.
MIDI is a real time protocol, so it is not a surprise that many applications using MIDI require only real time functionality. In this case, you may use the Drumstick::RT library, which is multiplatform. An example equivalent to the former one, but implemented using the Drumstick::RT library looks like this:
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
if (output != 0) {
qDebug() <<
"testing backend: " << output->
backendName();
qDebug() <<
"public name " << output->
publicName();
qDebug() << "port " << conn.first;
QList<int> note_list{ 60, 62, 64, 65, 67, 69, 71, 72 };
for(auto midi_note : note_list)
{
QThread::msleep(250);
}
}
return 0;
}
BackendManager class declaration.
The BackendManager class manages lists of dynamic and static backends for applications based on drums...
MIDIOutput * outputBackendByName(const QString name)
outputBackendByName
virtual QString backendName()=0
backendName
virtual void sendNoteOn(int chan, int note, int vel)=0
sendNoteOn 0x9
virtual QList< MIDIConnection > connections(bool advanced=false)=0
connections
virtual QString publicName()=0
publicName
virtual void open(const MIDIConnection &conn)=0
open the MIDI port by name
virtual void sendNoteOff(int chan, int note, int vel)=0
sendNoteOff 0x8
virtual void close()=0
close the MIDI port
Realtime MIDI output interface.
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 scheduling (that is why it is called a Sequencer).
#include <QCoreApplication>
int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
port->
setCapability( SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ );
int tick = 0;
QList<int> notelist{ 60, 62, 64, 65, 67, 69, 71, 72 };
for(auto midinote : notelist)
{
ev1.setSubscribers();
ev1.scheduleTick(queue->getId(), tick, false);
tick += 60;
ev2.setSubscribers();
ev2.scheduleTick(queue->getId(), tick, false);
}
delete client;
return 0;
}
Classes managing ALSA Sequencer ports.
Classes managing ALSA Sequencer queues.
void start()
Start the queue.
void stop()
Stop the queue.
QueueTempo & getTempo()
Gets a QueueTempo object reference.
void setTempo(const QueueTempo &value)
Applies a QueueTempo object to the queue.
void setPPQ(int value)
Sets the queue resolution in parts per quarter note.
void setNominalBPM(float value)
Sets the queue's nominal tempo in BPM (beats per minute).
MidiQueue * createQueue()
Create and return a new MidiQueue associated to this client.
void synchronizeOutput()
Wait until all sent events are processed.
To build a program using Drumstick, you may use CMake or Qmake. Using CMake you need first to build or install Drumstick on your development machine, and create a project file like the following, with the name: "CMakeLists.txt"
cmake_minimum_required(VERSION 3.16)
project(example LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core REQUIRED)
find_package(Drumstick COMPONENTS ALSA REQUIRED)
add_executable(example main.cpp)
target_link_libraries( example
Qt5::Core
Drumstick::ALSA
)
Assuming that you have Qt 5.12.9 installed at your $HOME/Qt directory, and Drumstick is installed at $HOME/Drumstick, then you can configure and build your project with these commands: (your current directory is your project's)
mkdir build
cmake -S . -B build -DCMAKE_PREFIX_PATH="$HOME/Qt/5.12.9/gcc_64;$HOME/Drumstick"
cmake --build build
If you prefer to download the Drumstick sources and build it, you can also build your project without needing to install Drumstick. In this case:
mkdir build
cmake -S . -B build -DCMAKE_PREFIX_PATH=$HOME/Qt/5.12.9/gcc_64 -DDrumstick_DIR=$HOME/Source/Drumstick/build
cmake --build .
To run your Drumstick::RT programs without installing Drumstick and your program, you may need to use an environment variable to indicate the location of the plugins, like this:
export DRUMSTICKRT=$HOME/Source/Drumstick/build/lib/drumstick2/
./example
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
- https://dmidiplayer.sourceforge.io
-
https://kmetronome.sourceforge.io
-
https://kmidimon.sourceforge.io
-
https://vmpk.sourceforge.io
-
https://wrk2mid.sourceforge.io
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>