drumstick-2.9.0/ 0000755 0001750 0001750 00000000000 14541630232 012533 5 ustar pedro pedro drumstick-2.9.0/cmake_admin/ 0000755 0001750 0001750 00000000000 14541630232 014763 5 ustar pedro pedro drumstick-2.9.0/cmake_admin/COPYING-CMAKE-SCRIPTS 0000644 0001750 0001750 00000002456 14541630232 017770 0 ustar pedro pedro Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
drumstick-2.9.0/cmake_admin/CustomBundleInfo.plist.in 0000644 0001750 0001750 00000002466 14541630232 021675 0 ustar pedro pedro
NSPrincipalClass
NSApplication
NSHighResolutionCapable
True
CFBundleDevelopmentRegion
English
CFBundleExecutable
${MACOSX_BUNDLE_EXECUTABLE_NAME}
CFBundleGetInfoString
${MACOSX_BUNDLE_INFO_STRING}
CFBundleIconFile
${MACOSX_BUNDLE_ICON_FILE}
CFBundleIdentifier
${MACOSX_BUNDLE_GUI_IDENTIFIER}
CFBundleInfoDictionaryVersion
6.0
CFBundleLongVersionString
${MACOSX_BUNDLE_LONG_VERSION_STRING}
CFBundleName
${MACOSX_BUNDLE_BUNDLE_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
${MACOSX_BUNDLE_SHORT_VERSION_STRING}
CFBundleSignature
????
CFBundleVersion
${MACOSX_BUNDLE_BUNDLE_VERSION}
CSResourcesFileMapped
NSHumanReadableCopyright
${MACOSX_BUNDLE_COPYRIGHT}
drumstick-2.9.0/cmake_admin/CustomFrameworkInfo.plist.in 0000644 0001750 0001750 00000001336 14541630232 022414 0 ustar pedro pedro
CFBundlePackageType
FMWK
CFBundleShortVersionString
${PROJECT_VERSION}
CFBundleVersion
${PROJECT_VERSION}
CFBundleGetInfoString
Created by CMake
CFBundleIdentifier
${MACOSX_FRAMEWORK_IDENTIFIER}
NSHumanReadableCopyright
© 2006-2021, Pedro López-Cabanillas and others
NOTE
Please, do NOT change this file -- It was generated by CMake.
drumstick-2.9.0/cmake_admin/FindSharedMimeInfo.cmake 0000644 0001750 0001750 00000005615 14541630232 021427 0 ustar pedro pedro # - Try to find the shared-mime-info package
#
# SHARED_MIME_INFO_MINIMUM_VERSION - Set this to the minimum version you need, default is 0.18
#
# Once done this will define
#
# SHARED_MIME_INFO_FOUND - system has the shared-mime-info package
# UPDATE_MIME_DATABASE_EXECUTABLE - the update-mime-database executable
# Copyright (c) 2007, Pino Toscano,
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# the minimum version of shared-mime-database we require
if (NOT SHARED_MIME_INFO_MINIMUM_VERSION)
set(SHARED_MIME_INFO_MINIMUM_VERSION "0.18")
endif (NOT SHARED_MIME_INFO_MINIMUM_VERSION)
if (UPDATE_MIME_DATABASE_EXECUTABLE)
# in cache already
set(SHARED_MIME_INFO_FOUND TRUE)
else (UPDATE_MIME_DATABASE_EXECUTABLE)
include (MacroEnsureVersion)
find_program (UPDATE_MIME_DATABASE_EXECUTABLE NAMES update-mime-database)
if (UPDATE_MIME_DATABASE_EXECUTABLE)
exec_program (${UPDATE_MIME_DATABASE_EXECUTABLE} ARGS -v RETURN_VALUE _null OUTPUT_VARIABLE _smiVersionRaw)
string(REGEX REPLACE "update-mime-database \\([a-zA-Z\\-]+\\) ([0-9]\\.[0-9]+).*"
"\\1" smiVersion "${_smiVersionRaw}")
set (SHARED_MIME_INFO_FOUND TRUE)
endif (UPDATE_MIME_DATABASE_EXECUTABLE)
if (SHARED_MIME_INFO_FOUND)
if (NOT SharedMimeInfo_FIND_QUIETLY)
message(STATUS "Found shared-mime-info version: ${smiVersion}")
macro_ensure_version(${SHARED_MIME_INFO_MINIMUM_VERSION} ${smiVersion} _smiVersion_OK)
if (NOT _smiVersion_OK)
message(FATAL_ERROR "The found version of shared-mime-info (${smiVersion}) is below the minimum required (${SHARED_MIME_INFO_MINIMUM_VERSION})")
endif (NOT _smiVersion_OK)
endif (NOT SharedMimeInfo_FIND_QUIETLY)
else (SHARED_MIME_INFO_FOUND)
if (SharedMimeInfo_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find shared-mime-info. See http://freedesktop.org/wiki/Software/shared-mime-info.")
endif (SharedMimeInfo_FIND_REQUIRED)
endif (SHARED_MIME_INFO_FOUND)
endif (UPDATE_MIME_DATABASE_EXECUTABLE)
mark_as_advanced(UPDATE_MIME_DATABASE_EXECUTABLE)
macro(UPDATE_XDG_MIMETYPES _path)
get_filename_component(_xdgmimeDir "${_path}" NAME)
if("${_xdgmimeDir}" STREQUAL packages )
get_filename_component(_xdgmimeDir "${_path}" PATH)
else("${_xdgmimeDir}" STREQUAL packages )
set(_xdgmimeDir "${_path}")
endif("${_xdgmimeDir}" STREQUAL packages )
install(CODE "
set(DESTDIR_VALUE \"\$ENV{DESTDIR}\")
if (NOT DESTDIR_VALUE)
# under Windows relative paths are used, that's why it runs from CMAKE_INSTALL_PREFIX
execute_process(COMMAND ${UPDATE_MIME_DATABASE_EXECUTABLE} ${_xdgmimeDir}
WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}\")
endif (NOT DESTDIR_VALUE)
")
endmacro (UPDATE_XDG_MIMETYPES)
drumstick-2.9.0/cmake_admin/MacroEnsureVersion.cmake 0000644 0001750 0001750 00000011735 14541630232 021565 0 ustar pedro pedro # This file defines the following macros for developers to use in ensuring
# that installed software is of the right version:
#
# MACRO_ENSURE_VERSION - test that a version number is greater than
# or equal to some minimum
# MACRO_ENSURE_VERSION_RANGE - test that a version number is greater than
# or equal to some minimum and less than some
# maximum
# MACRO_ENSURE_VERSION2 - deprecated, do not use in new code
#
# MACRO_ENSURE_VERSION
# This macro compares version numbers of the form "x.y.z" or "x.y"
# MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK)
# will set FOO_VERSION_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION
# Leading and trailing text is ok, e.g.
# MACRO_ENSURE_VERSION( "2.5.31" "flex 2.5.4a" VERSION_OK)
# which means 2.5.31 is required and "flex 2.5.4a" is what was found on the system
# Copyright (c) 2006, David Faure,
# Copyright (c) 2007, Will Stephenson
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# MACRO_ENSURE_VERSION_RANGE
# This macro ensures that a version number of the form
# "x.y.z" or "x.y" falls within a range defined by
# min_version <= found_version < max_version.
# If this expression holds, FOO_VERSION_OK will be set TRUE
#
# Example: MACRO_ENSURE_VERSION_RANGE3( "0.1.0" ${FOOCODE_VERSION} "0.7.0" FOO_VERSION_OK )
#
# This macro will break silently if any of x,y,z are greater than 100.
#
# Copyright (c) 2007, Will Stephenson
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# NORMALIZE_VERSION
# Helper macro to convert version numbers of the form "x.y.z"
# to an integer equal to 10^4 * x + 10^2 * y + z
#
# This macro will break silently if any of x,y,z are greater than 100.
#
# Copyright (c) 2006, David Faure,
# Copyright (c) 2007, Will Stephenson
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# CHECK_RANGE_INCLUSIVE_LOWER
# Helper macro to check whether x <= y < z
#
# Copyright (c) 2007, Will Stephenson
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
MACRO(NORMALIZE_VERSION _requested_version _normalized_version)
STRING(REGEX MATCH "[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" _threePartMatch "${_requested_version}")
if (_threePartMatch)
# parse the parts of the version string
STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" _major_vers "${_requested_version}")
STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" _minor_vers "${_requested_version}")
STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" _patch_vers "${_requested_version}")
else (_threePartMatch)
STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+" "\\1" _major_vers "${_requested_version}")
STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)" "\\1" _minor_vers "${_requested_version}")
set(_patch_vers "0")
endif (_threePartMatch)
# compute an overall version number which can be compared at once
MATH(EXPR ${_normalized_version} "${_major_vers}*10000 + ${_minor_vers}*100 + ${_patch_vers}")
ENDMACRO(NORMALIZE_VERSION)
MACRO(MACRO_CHECK_RANGE_INCLUSIVE_LOWER _lower_limit _value _upper_limit _ok)
if (${_value} LESS ${_lower_limit})
set( ${_ok} FALSE )
elseif (${_value} EQUAL ${_lower_limit})
set( ${_ok} TRUE )
elseif (${_value} EQUAL ${_upper_limit})
set( ${_ok} FALSE )
elseif (${_value} GREATER ${_upper_limit})
set( ${_ok} FALSE )
else (${_value} LESS ${_lower_limit})
set( ${_ok} TRUE )
endif (${_value} LESS ${_lower_limit})
ENDMACRO(MACRO_CHECK_RANGE_INCLUSIVE_LOWER)
MACRO(MACRO_ENSURE_VERSION requested_version found_version var_too_old)
NORMALIZE_VERSION( ${requested_version} req_vers_num )
NORMALIZE_VERSION( ${found_version} found_vers_num )
if (found_vers_num LESS req_vers_num)
set( ${var_too_old} FALSE )
else (found_vers_num LESS req_vers_num)
set( ${var_too_old} TRUE )
endif (found_vers_num LESS req_vers_num)
ENDMACRO(MACRO_ENSURE_VERSION)
MACRO(MACRO_ENSURE_VERSION2 requested_version2 found_version2 var_too_old2)
MACRO_ENSURE_VERSION( ${requested_version2} ${found_version2} ${var_too_old2})
ENDMACRO(MACRO_ENSURE_VERSION2)
MACRO(MACRO_ENSURE_VERSION_RANGE min_version found_version max_version var_ok)
NORMALIZE_VERSION( ${min_version} req_vers_num )
NORMALIZE_VERSION( ${found_version} found_vers_num )
NORMALIZE_VERSION( ${max_version} max_vers_num )
MACRO_CHECK_RANGE_INCLUSIVE_LOWER( ${req_vers_num} ${found_vers_num} ${max_vers_num} ${var_ok})
ENDMACRO(MACRO_ENSURE_VERSION_RANGE)
drumstick-2.9.0/cmake_admin/cmake_uninstall.cmake.in 0000644 0001750 0001750 00000001555 14541630232 021551 0 ustar pedro pedro IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
STRING(REGEX REPLACE "\n" ";" files "${files}")
FOREACH(file ${files})
MESSAGE(STATUS "Uninstalling \"${file}\"")
IF(EXISTS "${file}")
EXEC_PROGRAM(
"@CMAKE_COMMAND@" ARGS "-E remove \"${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
IF("${rm_retval}" STREQUAL 0)
ELSE("${rm_retval}" STREQUAL 0)
MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"")
ENDIF("${rm_retval}" STREQUAL 0)
ELSE(EXISTS "${file}")
MESSAGE(STATUS "File \"${file}\" does not exist.")
ENDIF(EXISTS "${file}")
ENDFOREACH(file)
drumstick-2.9.0/cmake_admin/CreateManpages.cmake 0000644 0001750 0001750 00000003173 14541630232 020650 0 ustar pedro pedro #[===========================================================================[
MIDI C++ Library
Copyright (C) 2005-2023 Pedro Lopez-Cabanillas
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 3 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, see .
#]===========================================================================]
MACRO(CREATE_MANPAGES)
SET(outfiles)
FOREACH (it ${ARGN})
GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
SET(outfile ${CMAKE_CURRENT_BINARY_DIR}/${outfile}.1)
SET(outfiles ${outfiles} ${outfile})
ADD_CUSTOM_COMMAND( OUTPUT ${outfile}
COMMAND ${XSLTPROC_EXECUTABLE}
--nonet --xinclude --xincludestyle
--output ${outfile}
http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
${infile}
DEPENDS ${infile})
ENDFOREACH (it)
ADD_CUSTOM_TARGET(manpages ALL DEPENDS ${outfiles})
INSTALL ( FILES ${outfiles}
DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" )
ENDMACRO(CREATE_MANPAGES)
drumstick-2.9.0/cmake_admin/SCMRevision.cmake 0000644 0001750 0001750 00000003404 14541630232 020127 0 ustar pedro pedro #[===========================================================================[
MIDI C++ Library
Copyright (C) 2005-2023 Pedro Lopez-Cabanillas
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 3 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, see .
#]===========================================================================]
find_package(Subversion QUIET)
if (Subversion_FOUND)
Subversion_WC_INFO(${PROJECT_SOURCE_DIR} PROJECT IGNORE_SVN_FAILURE)
if (DEFINED PROJECT_WC_REVISION)
message(STATUS "Current revision (SVN) is ${PROJECT_WC_REVISION}")
endif()
endif()
if (NOT DEFINED PROJECT_WC_REVISION)
find_package(Git QUIET)
if (Git_FOUND)
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse --short HEAD
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE PROJECT_WC_REVISION
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (${res} EQUAL 0)
message(STATUS "Current revision (Git) is ${PROJECT_WC_REVISION}")
else()
unset(PROJECT_WC_REVISION)
endif()
endif()
endif()
if (DEFINED PROJECT_WC_REVISION)
set(${PROJECT_NAME}_WC_REVISION ${PROJECT_WC_REVISION})
endif()
drumstick-2.9.0/library/ 0000755 0001750 0001750 00000000000 14541630232 014177 5 ustar pedro pedro drumstick-2.9.0/library/Info.plist.lib 0000644 0001750 0001750 00000001533 14541630232 016716 0 ustar pedro pedro
CFBundlePackageType
FMWK
CFBundleShortVersionString
@FULL_VERSION@
CFBundleVersion
@FULL_VERSION@
CFBundleGetInfoString
Created by Qt/QMake
CFBundleSignature
@TYPEINFO@
CFBundleExecutable
@LIBRARY@
CFBundleIdentifier
@BUNDLEIDENTIFIER@
NSHumanReadableCopyright
© 2006-2019, Pedro López-Cabanillas and others
NOTE
Please, do NOT change this file -- It was generated by Qt/QMake.
drumstick-2.9.0/library/alsa/ 0000755 0001750 0001750 00000000000 14541630232 015117 5 ustar pedro pedro drumstick-2.9.0/library/alsa/alsa.pro 0000644 0001750 0001750 00000002023 14541630232 016556 0 ustar pedro pedro TEMPLATE = lib
TARGET = drumstick-alsa
DESTDIR = ../../build/lib
DEPENDPATH += . ../include
INCLUDEPATH += . ../include
include (../../global.pri)
QT -= gui
#QT += dbus
CONFIG += c++11 qt thread link_pkgconfig create_pc create_prl no_install_prl
static {
CONFIG += staticlib
}
DEFINES += drumstick_alsa_EXPORTS #RTKIT_SUPPORT
QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS_HIDESYMS
QMAKE_PKGCONFIG_PREFIX = $$INSTALLBASE
# Input
HEADERS += \
../include/drumstick.h \
../include/drumstick/alsaclient.h \
../include/drumstick/alsaevent.h \
../include/drumstick/alsaport.h \
../include/drumstick/alsaqueue.h \
../include/drumstick/alsatimer.h \
../include/drumstick/macros.h \
../include/drumstick/playthread.h \
../include/drumstick/subscription.h \
../include/drumstick/sequencererror.h \
errorcheck.h
SOURCES += \
alsaclient.cpp \
alsaevent.cpp \
alsaport.cpp \
alsaqueue.cpp \
alsatimer.cpp \
playthread.cpp \
sequencererror.cpp \
subscription.cpp
linux:PKGCONFIG += alsa
drumstick-2.9.0/library/alsa/alsaqueue.cpp 0000644 0001750 0001750 00000051676 14541630232 017627 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include "errorcheck.h"
#include
#include
#include
#include
#include
/**
* @file alsaqueue.cpp
* Implementation of classes managing ALSA Sequencer queues
*/
namespace drumstick {
namespace ALSA {
/**
* This is the value for the base skew used in ALSA. It is not possible
* to assign an arbitrary value (ALSA version <= 1.0.20).
*/
const unsigned int SKEW_BASE = 0x10000;
/**
* @addtogroup ALSAQueue
* @{
*
* ALSA events can be delivered to the output ports at scheduled times using the
* queues. There is a small amount of available queues in the system, so this is
* a limited resource. Queues are also used to time-stamp incoming events.
*
* Classes:
*
* QueueInfo holds several properties about the queue object.
*
* QueueStatus is used to retrieve the status of the queue object.
*
* QueueTempo holds properties to get and set the tempo in the queue object.
*
* QueueTimer holds properties about the Timer used in the queue object.
*
* MidiQueue represents the queue object.
*
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_queue.html
* @}
*/
/**
* Default constructor
*/
QueueInfo::QueueInfo()
{
snd_seq_queue_info_malloc(&m_Info);
}
/**
* Constructor.
* @param other ALSA queue info object pointer
*/
QueueInfo::QueueInfo(snd_seq_queue_info_t* other)
{
snd_seq_queue_info_malloc(&m_Info);
snd_seq_queue_info_copy(m_Info, other);
}
/**
* Copy constructor.
* @param other An existing QueueInfo object reference.
*/
QueueInfo::QueueInfo(const QueueInfo& other)
{
snd_seq_queue_info_malloc(&m_Info);
snd_seq_queue_info_copy(m_Info, other.m_Info);
}
/**
* Destructor
*/
QueueInfo::~QueueInfo()
{
snd_seq_queue_info_free(m_Info);
}
/**
* Copy the current object and return the copy.
* @return The pointer to the new object.
*/
QueueInfo* QueueInfo::clone()
{
return new QueueInfo(m_Info);
}
/**
* Assignment operator.
* @param other An existing QueueInfo object reference.
* @return This object.
*/
QueueInfo& QueueInfo::operator=(const QueueInfo& other)
{
if (this == &other)
return *this;
snd_seq_queue_info_copy(m_Info, other.m_Info);
return *this;
}
/**
* Gets the queue's numeric identifier.
* @return The numeric identifier.
*/
int QueueInfo::getId()
{
return snd_seq_queue_info_get_queue(m_Info);
}
/**
* Gets the queue name
* @return The queue name.
*/
QString QueueInfo::getName()
{
return QString(snd_seq_queue_info_get_name(m_Info));
}
/**
* Gets the owner's client id of the queue.
* @return the owner's client id.
*/
int QueueInfo::getOwner()
{
return snd_seq_queue_info_get_owner(m_Info);
}
/**
* Returns the locking status of the queue
* @return The locking status.
*/
bool QueueInfo::isLocked()
{
return (snd_seq_queue_info_get_locked(m_Info) != 0);
}
/**
* Gets the flags of the queue.
* @return The flags of the queue.
*/
unsigned int QueueInfo::getFlags()
{
return snd_seq_queue_info_get_flags(m_Info);
}
/**
* Sets the queue name
* @param value The queue name
*/
void QueueInfo::setName(QString value)
{
snd_seq_queue_info_set_name(m_Info, value.toLocal8Bit().data());
}
/**
* Sets the client ID of the owner
* @param value The client ID of the owner
*/
void QueueInfo::setOwner(int value)
{
snd_seq_queue_info_set_owner(m_Info, value);
}
/**
* Sets the bit flags of the queue
* @param value The bit flags
*/
void QueueInfo::setFlags(unsigned int value)
{
snd_seq_queue_info_set_flags(m_Info, value);
}
/**
* Sets the locked status of the queue
* @param locked The locked status
*/
void QueueInfo::setLocked(bool locked)
{
snd_seq_queue_info_set_locked(m_Info, locked ? 1 : 0);
}
/**
* Gets the size of the ALSA queue info object.
* @return The size of the ALSA object.
*/
int QueueInfo::getInfoSize() const
{
return snd_seq_queue_info_sizeof();
}
/**
* Default constructor
*/
QueueStatus::QueueStatus()
{
snd_seq_queue_status_malloc(&m_Info);
}
/**
* Constructor
* @param other ALSA queue status object pointer
*/
QueueStatus::QueueStatus(snd_seq_queue_status_t* other)
{
snd_seq_queue_status_malloc(&m_Info);
snd_seq_queue_status_copy(m_Info, other);
}
/**
* Copy constructor
* @param other An existing QueueStatus object reference
*/
QueueStatus::QueueStatus(const QueueStatus& other)
{
snd_seq_queue_status_malloc(&m_Info);
snd_seq_queue_status_copy(m_Info, other.m_Info);
}
/**
* Destructor
*/
QueueStatus::~QueueStatus()
{
snd_seq_queue_status_free(m_Info);
}
/**
* Copy the current object and return the copy
* @return The pointer to the new object
*/
QueueStatus* QueueStatus::clone()
{
return new QueueStatus(m_Info);
}
/**
* Assignment operator
* @param other An existing QueueStatus object reference
* @return This object
*/
QueueStatus& QueueStatus::operator=(const QueueStatus& other)
{
if (this == &other)
return *this;
snd_seq_queue_status_copy(m_Info, other.m_Info);
return *this;
}
/**
* Gets the queue's numeric identifier
* @return The queue's numeric identifier.
*/
int QueueStatus::getId()
{
return snd_seq_queue_status_get_queue(m_Info);
}
/**
* Gets the number of queued events
* @return The number of queued events
*/
int QueueStatus::getEvents()
{
return snd_seq_queue_status_get_events(m_Info);
}
/**
* Gets the real time (secods and nanoseconds) of the queue
* @return The queue's real time.
*/
const snd_seq_real_time_t* QueueStatus::getRealtime()
{
return snd_seq_queue_status_get_real_time(m_Info);
}
/**
* Gets the running status bits
* @return The running status bits
*/
unsigned int QueueStatus::getStatusBits()
{
return snd_seq_queue_status_get_status(m_Info);
}
/**
* Gets the musical time (ticks) of the queue
* @return The musical time
*/
snd_seq_tick_time_t QueueStatus::getTickTime()
{
return snd_seq_queue_status_get_tick_time(m_Info);
}
/**
* Gets the size of the ALSA status object
* @return The size of the ALSA object
*/
int QueueStatus::getInfoSize() const
{
return snd_seq_queue_status_sizeof();
}
/**
* Gets the queue's running state
* @return True if the queue is running
*/
bool QueueStatus::isRunning()
{
return (snd_seq_queue_status_get_status(m_Info) != 0);
}
/**
* Gets the clock time in seconds of the queue
* @return The queue time in seconds
*/
double QueueStatus::getClockTime()
{
const snd_seq_real_time_t* time = snd_seq_queue_status_get_real_time(m_Info);
return (time->tv_sec * 1.0) + (time->tv_nsec * 1.0e-9);
}
/**
* Default constructor
*/
QueueTempo::QueueTempo()
{
snd_seq_queue_tempo_malloc(&m_Info);
}
/**
* Constructor
* @param other An ALSA queue tempo object pointer
*/
QueueTempo::QueueTempo(snd_seq_queue_tempo_t* other)
{
snd_seq_queue_tempo_malloc(&m_Info);
snd_seq_queue_tempo_copy(m_Info, other);
}
/**
* Copy constructor
* @param other An existing QueueTempo object reference
*/
QueueTempo::QueueTempo(const QueueTempo& other)
{
snd_seq_queue_tempo_malloc(&m_Info);
snd_seq_queue_tempo_copy(m_Info, other.m_Info);
}
/**
* Destructor
*/
QueueTempo::~QueueTempo()
{
snd_seq_queue_tempo_free(m_Info);
}
/**
* Copy the current object returning the copied object
* @return The pointer to the new object
*/
QueueTempo* QueueTempo::clone()
{
return new QueueTempo(m_Info);
}
/**
* Assignment operator
* @param other An existing QueueTempo object reference
* @return This object
*/
QueueTempo& QueueTempo::operator=(const QueueTempo& other)
{
if (this == &other)
return *this;
snd_seq_queue_tempo_copy(m_Info, other.m_Info);
return *this;
}
/**
* Gets the queue's numeric identifier
* @return The queue's numeric identifier
*/
int QueueTempo::getId()
{
return snd_seq_queue_tempo_get_queue(m_Info);
}
/**
* Gets the PPQ (parts per quarter note) resolution of the queue
* @return The PPQ (parts per quarter note) resolution
*/
int QueueTempo::getPPQ()
{
return snd_seq_queue_tempo_get_ppq(m_Info);
}
/**
* Gets the tempo skew numerator. The real skew factor is the quotient of this
* value divided by the skew base.
* @return The tempo skew numerator.
* @see getSkewBase(), setSkewValue(), setTempoFactor()
*/
unsigned int QueueTempo::getSkewValue()
{
return snd_seq_queue_tempo_get_skew(m_Info);
}
/**
* Gets the tempo skew base. The real skew factor is the quotient of the skew
* value divided by the skew base.
* @return The tempo skew base.
* @see getSkewValue(), setSkewValue(), setTempoFactor()
*/
unsigned int QueueTempo::getSkewBase()
{
return snd_seq_queue_tempo_get_skew_base(m_Info);
}
/**
* Gets the queue's tempo in microseconds per beat.
* @return The queue's tempo in microseconds per beat.
*/
unsigned int QueueTempo::getTempo()
{
return snd_seq_queue_tempo_get_tempo(m_Info);
}
/**
* Sets the queue resolution in parts per quarter note.
* @param value The queue resolution in PPQ.
*/
void QueueTempo::setPPQ(int value)
{
snd_seq_queue_tempo_set_ppq(m_Info, value);
}
/**
* Sets the tempo skew numerator. The real skew factor is the quotient of this
* value divided by the skew base.
* @param value The tempo skew numerator.
* @see getSkewBase(), getSkewValue(), setTempoFactor()
*/
void QueueTempo::setSkewValue(unsigned int value)
{
snd_seq_queue_tempo_set_skew(m_Info, value);
}
/**
* Sets the tempo skew base. The real skew factor is the quotient of the skew
* value divided by the skew base.
* @bug Protected because ALSA only accepts as argument a constant SKEW_BASE
* @param value The tempo skew base.
* @see getSkewBase(), getSkewValue(), setTempoFactor()
*/
void QueueTempo::setSkewBase(unsigned int value)
{
snd_seq_queue_tempo_set_skew_base(m_Info, value);
}
/**
* Sets the queue tempo in microseconds per beat
* @param value The tempo in microseconds per beat
*/
void QueueTempo::setTempo(unsigned int value)
{
snd_seq_queue_tempo_set_tempo(m_Info, value);
}
/**
* Gets the queue's nominal BPM tempo (in beats per minute)
* @return The queue's nominal BPM tempo (in beats per minute)
*/
float QueueTempo::getNominalBPM()
{
int itempo = getTempo();
if (itempo != 0)
return 6.0e7f / itempo;
return 0.0f;
}
/**
* Gets the queue's real BPM tempo in beats per minute. The result is equal to
* the nominal BPM tempo multiplied by the skew factor.
* @return
*/
float QueueTempo::getRealBPM()
{
float tempo = getNominalBPM();
return tempo * getSkewValue() / SKEW_BASE;
}
/**
* Sets the queue's tempo skew factor
* @param value The tempo skew factor.
*/
void QueueTempo::setTempoFactor(float value)
{
setSkewValue(floor(SKEW_BASE * value));
setSkewBase(SKEW_BASE);
}
/**
* Sets the queue's nominal tempo in BPM (beats per minute).
* @param value The nominal tempo in BPM (beats per minute).
*/
void QueueTempo::setNominalBPM(float value)
{
setTempo(floor(6.0e7f / value));
}
/**
* Gets the size of the ALSA queue tempo object
* @return The size of the ALSA object
*/
int QueueTempo::getInfoSize() const
{
return snd_seq_queue_tempo_sizeof();
}
/**
* Default constructor
*/
QueueTimer::QueueTimer()
{
snd_seq_queue_timer_malloc(&m_Info);
}
/**
* Constructor
* @param other An ALSA queue timer object pointer
*/
QueueTimer::QueueTimer(snd_seq_queue_timer_t* other)
{
snd_seq_queue_timer_malloc(&m_Info);
snd_seq_queue_timer_copy(m_Info, other);
}
/**
* Copy constructor
* @param other An existing QueueTimer object reference
*/
QueueTimer::QueueTimer(const QueueTimer& other)
{
snd_seq_queue_timer_malloc(&m_Info);
snd_seq_queue_timer_copy(m_Info, other.m_Info);
}
/**
* Destructor
*/
QueueTimer::~QueueTimer()
{
snd_seq_queue_timer_free(m_Info);
}
/**
* Copy the current object and return the copy
* @return The pointer to the new object
*/
QueueTimer* QueueTimer::clone()
{
return new QueueTimer(m_Info);
}
/**
* Assignment operator
* @param other An existing QueueTimer object reference
* @return This object
*/
QueueTimer& QueueTimer::operator=(const QueueTimer& other)
{
if (this == &other)
return *this;
snd_seq_queue_timer_copy(m_Info, other.m_Info);
return *this;
}
/**
* The queue's numeric identifier
* @return The queue's numeric identifier
*/
int QueueTimer::getQueueId()
{
return snd_seq_queue_timer_get_queue(m_Info);
}
/**
* Gets the timer type.
*
* The timer type can be one of the following constants:
*
* - SND_SEQ_TIMER_ALSA: ALSA timer
* - SND_SEQ_TIMER_MIDI_CLOCK: MIDI Clock (CLOCK event)
* - SND_SEQ_TIMER_MIDI_TICK: MIDI Timer Tick (TICK event)
*
* @return the timer type.
* @see setType()
*/
snd_seq_queue_timer_type_t QueueTimer::getType()
{
return snd_seq_queue_timer_get_type(m_Info);
}
/**
* Gets the timer identifier record
* @return The timer identifier record pointer
*/
const snd_timer_id_t* QueueTimer::getId()
{
return snd_seq_queue_timer_get_id(m_Info);
}
/**
* Gets the timer resolution
* @return The timer resolution
*/
unsigned int QueueTimer::getResolution()
{
return snd_seq_queue_timer_get_resolution(m_Info);
}
/**
* Sets the timer type.
* The timer type can be one of the following constants:
*
* - SND_SEQ_TIMER_ALSA: ALSA timer
* - SND_SEQ_TIMER_MIDI_CLOCK: MIDI Clock (CLOCK event)
* - SND_SEQ_TIMER_MIDI_TICK: MIDI Timer Tick (TICK event)
*
* @param value The timer type
* @see getType()
*/
void QueueTimer::setType(snd_seq_queue_timer_type_t value)
{
snd_seq_queue_timer_set_type(m_Info, value);
}
/**
* Sets the timer identifier record
* @param value The timer identifier record pointer
*/
void QueueTimer::setId(snd_timer_id_t* value)
{
snd_seq_queue_timer_set_id(m_Info, value);
}
/**
* Sets the timer identifier
* @param id Timer identifier object
* @since 0.3.0
*/
void QueueTimer::setId(const TimerId& id)
{
setId(id.m_Info);
}
/**
* Sets the timer resolution
* @param value The timer resolution
*/
void QueueTimer::setResolution(unsigned int value)
{
snd_seq_queue_timer_set_resolution(m_Info, value);
}
/**
* Gets the size of the ALSA queue timer object
* @return The size of the ALSA object
*/
int QueueTimer::getInfoSize() const
{
return snd_seq_queue_timer_sizeof();
}
/**
* Constructor
* @param seq An existing MidiClient instance
* @param parent An optional parent object
*/
MidiQueue::MidiQueue(MidiClient* seq, QObject* parent)
: QObject(parent)
{
m_MidiClient = seq;
m_Id = DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_alloc_queue(m_MidiClient->getHandle()));
m_allocated = !(m_Id < 0);
}
/**
* Constructor
* @param seq An existing MidiClient instance
* @param info A QueueInfo object reference
* @param parent An optional parent object
*/
MidiQueue::MidiQueue(MidiClient* seq, const QueueInfo& info, QObject* parent)
: QObject(parent)
{
m_MidiClient = seq;
m_Info = info;
m_Id = DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_create_queue(m_MidiClient->getHandle(), m_Info.m_Info));
m_allocated = !(m_Id < 0);
}
/**
* Constructor
* @param seq An existing MidiClient instance
* @param name The name for the new queue
* @param parent An optional parent object
*/
MidiQueue::MidiQueue(MidiClient* seq, const QString name, QObject* parent)
: QObject(parent)
{
m_MidiClient = seq;
m_Id = DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_alloc_named_queue(m_MidiClient->getHandle(), name.toLocal8Bit().data()));
m_allocated = !(m_Id < 0);
}
/**
* Constructor.
*
* Note: this constructor doesn't allocate a new queue, it uses an existing one.
* @param seq An existing MidiClient instance
* @param queue_id An existing queue numeric identifier
* @param parent An optional parent object
*/
MidiQueue::MidiQueue(MidiClient* seq, const int queue_id, QObject* parent)
: QObject(parent)
{
m_MidiClient = seq;
m_Id = queue_id;
m_allocated = false;
}
/**
* Destructor
*/
MidiQueue::~MidiQueue()
{
if ( m_allocated && (m_MidiClient->getHandle() != nullptr) )
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_free_queue(m_MidiClient->getHandle(), m_Id));
}
}
/**
* Gets a QueueInfo object reference
* @return A QueueInfo object reference
*/
QueueInfo& MidiQueue::getInfo()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_info(m_MidiClient->getHandle(), m_Id, m_Info.m_Info));
return m_Info;
}
/**
* Gets a QueueStatus object reference
* @return A QueueStatus object reference
*/
QueueStatus& MidiQueue::getStatus()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_status(m_MidiClient->getHandle(), m_Id, m_Status.m_Info));
return m_Status;
}
/**
* Gets a QueueTempo object reference
* @return A QueueTempo object reference
*/
QueueTempo& MidiQueue::getTempo()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_tempo(m_MidiClient->getHandle(), m_Id, m_Tempo.m_Info));
return m_Tempo;
}
/**
* Gets a QueueTimer object reference
* @return A QueueTimer object reference
*/
QueueTimer& MidiQueue::getTimer()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_timer(m_MidiClient->getHandle(), m_Id, m_Timer.m_Info));
return m_Timer;
}
/**
* Applies a QueueInfo object to the queue
* @param value A QueueInfo object reference
*/
void MidiQueue::setInfo(const QueueInfo& value)
{
m_Info = value;
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_info(m_MidiClient->getHandle(), m_Id, m_Info.m_Info));
}
/**
* Applies a QueueTempo object to the queue
* @param value A QueueTempo object reference
*/
void MidiQueue::setTempo(const QueueTempo& value)
{
m_Tempo = value;
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_tempo(m_MidiClient->getHandle(), m_Id, m_Tempo.m_Info));
}
/**
* Applies q QueueTimer object to the queue
* @param value A QueueTimer object reference
*/
void MidiQueue::setTimer(const QueueTimer& value)
{
m_Timer = value;
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_timer(m_MidiClient->getHandle(), m_Id, m_Timer.m_Info));
}
/**
* Gets the queue usage flag.
*
* @return 1 = client is allowed to access the queue, 0 = not allowed.
*/
int MidiQueue::getUsage()
{
return DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_queue_usage(m_MidiClient->getHandle(), m_Id));
}
/**
* Sets the queue usage flag.
*
* @param used 1 = client is allowed to access the queue, 0 = not allowed.
*/
void MidiQueue::setUsage(int used)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_queue_usage(m_MidiClient->getHandle(), m_Id, used));
}
/**
* Start the queue.
*
* This method should start running the queue from the initial position.
*/
void MidiQueue::start()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_start_queue(m_MidiClient->getHandle(), m_Id, nullptr));
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(m_MidiClient->getHandle()));
}
/**
* Stop the queue.
*
* This method should stop running the queue.
*/
void MidiQueue::stop()
{
if (m_MidiClient != nullptr && m_MidiClient->getHandle() != nullptr) {
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_stop_queue(m_MidiClient->getHandle(), m_Id, nullptr));
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(m_MidiClient->getHandle()));
}
}
/**
* Start the queue without resetting the last position.
*
* This method should start running the queue from the last position set.
*/
void MidiQueue::continueRunning()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_continue_queue(m_MidiClient->getHandle(), m_Id, nullptr));
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(m_MidiClient->getHandle()));
}
/**
* Clear the queue, dropping any scheduled events.
*/
void MidiQueue::clear()
{
if (m_MidiClient != nullptr && m_MidiClient->getHandle() != nullptr)
snd_seq_drop_output(m_MidiClient->getHandle());
}
/**
* Sets the queue position in musical time (ticks).
* @param pos Musical time in ticks.
*/
void MidiQueue::setTickPosition(snd_seq_tick_time_t pos)
{
SystemEvent event(SND_SEQ_EVENT_SETPOS_TICK);
snd_seq_ev_set_queue_pos_tick(event.getHandle(), m_Id, pos);
event.setDirect();
m_MidiClient->outputDirect(&event);
}
/**
* Sets the queue position in real time (clock) units: seconds and nanoseconds.
* @param pos Real time (clock) position in seconds/nanoseconds.
*/
void MidiQueue::setRealTimePosition(snd_seq_real_time_t* pos)
{
SystemEvent event(SND_SEQ_EVENT_SETPOS_TIME);
snd_seq_ev_set_queue_pos_real(event.getHandle(), m_Id, pos);
event.setDirect();
m_MidiClient->outputDirect(&event);
}
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/alsa/drumstick-alsa-config.cmake 0000644 0001750 0001750 00000000201 14541630232 022300 0 ustar pedro pedro include(CMakeFindDependencyMacro)
find_dependency(ALSA REQUIRED)
include(${CMAKE_CURRENT_LIST_DIR}/drumstick-alsa-targets.cmake)
drumstick-2.9.0/library/alsa/errorcheck.h 0000644 0001750 0001750 00000004501 14541630232 017417 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef ERRORCHECK_H
#define ERRORCHECK_H
extern "C" {
#include
}
#include
#include
#include
/**
* @file errorcheck.h
* Error checking functions and macros
*/
namespace drumstick { namespace ALSA {
/**
* @addtogroup ALSAError
* @{
*/
/**
* Checks the error code for severe errors.
* If the provided error code is less than zero an exception is thrown,
* containing both the error code and the location.
* @param rc Error code
* @param where Location
* @return Error code
*/
inline int checkErrorAndThrow(int rc, const char *where)
{
if (rc < 0) {
qDebug() << "Error code:" << rc << "(" << snd_strerror(rc) << ")";
qDebug() << "Location:" << where;
throw SequencerError(QString(where), rc);
}
return rc;
}
/**
* Check the error code for warning errors.
* This method doesn't throw an exception.
* @param rc Error code
* @param where Location
* @return Error code
*/
inline int checkWarning(int rc, const char *where)
{
if (rc < 0) {
qWarning() << "Exception code:" << rc << "(" << snd_strerror(rc) << ")";
qWarning() << "Location:" << where;
}
return rc;
}
/**
* This macro calls the check error function.
* @param x Error code
*/
#define DRUMSTICK_ALSA_CHECK_ERROR(x) (checkErrorAndThrow((x),__PRETTY_FUNCTION__))
/**
* This macro calls the check warning function.
* @param x Error code
*/
#define DRUMSTICK_ALSA_CHECK_WARNING(x) (checkWarning((x),__PRETTY_FUNCTION__))
/** @} */
}} // namespace drumstick::ALSA
#endif // ERRORCHECK_H
drumstick-2.9.0/library/alsa/sequencererror.cpp 0000644 0001750 0001750 00000002671 14541630232 020675 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
extern "C" {
#include
}
#include
/**
* @file sequencererror.cpp
* SequencerError Exception class implementation
*/
namespace drumstick { namespace ALSA {
/**
* @addtogroup ALSAError
* @{
*/
SequencerError::SequencerError(QString const& s, int rc):
m_location(s), m_errCode(rc) { }
const char *SequencerError::what() const noexcept
{
return snd_strerror(m_errCode);
}
QString SequencerError::qstrError() const
{
return QString(what());
}
int SequencerError::code() const
{
return m_errCode;
}
const QString &SequencerError::location() const
{
return m_location;
}
/** @} */
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/alsa/subscription.cpp 0000644 0001750 0001750 00000026532 14541630232 020357 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include "errorcheck.h"
#include
/**
* @file subscription.cpp
* Implementation of classes managing ALSA sequencer subscriptions
*/
/** @ingroup ALSAGroup */
namespace drumstick {
namespace ALSA {
/**
* @addtogroup ALSASubs
* @{
*
* Subscriptions are virtual MIDI cables between readable and writable ports.
*
* The ALSA sequencer readable ports are equivalent to the MIDI OUT ports in the
* real world. Similarly, the writable ports are equivalent to the MIDI IN ones.
* Subscriptions, like real MIDI cables, always involve a readable port (source)
* and a writable port (destination).
*
* Classes:
*
* Subscriber: This class is used to enumerate the subscribers of a given (root) port.
*
* Subscription: This class represents a connection between two ports.
*
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_subscribe.html
* @}
*/
/**
* Default constructor
*/
Subscriber::Subscriber()
{
snd_seq_query_subscribe_malloc(&m_Info);
}
/**
* Copy constructor
* @param other Existing Subscriber object reference
*/
Subscriber::Subscriber(const Subscriber& other)
{
snd_seq_query_subscribe_malloc(&m_Info);
snd_seq_query_subscribe_copy(m_Info, other.m_Info);
}
/**
* Constructor
* @param other Pointer to an ALSA query subscribe object
*/
Subscriber::Subscriber(snd_seq_query_subscribe_t* other)
{
snd_seq_query_subscribe_malloc(&m_Info);
snd_seq_query_subscribe_copy(m_Info, other);
}
/**
* Destructor
*/
Subscriber::~Subscriber()
{
snd_seq_query_subscribe_free(m_Info);
}
/**
* Copy the current object
* @return Pointer to the new object
*/
Subscriber* Subscriber::clone()
{
return new Subscriber(m_Info);
}
/**
* Assignment operator
* @param other Existing Subscriber object reference
* @return This object
*/
Subscriber& Subscriber::operator=(const Subscriber& other)
{
if (this == &other)
return *this;
snd_seq_query_subscribe_copy(m_Info, other.m_Info);
return *this;
}
/**
* Gets the subscriber's client number
* @return Client number
*/
int
Subscriber::getClient()
{
return snd_seq_query_subscribe_get_client(m_Info);
}
/**
* Gets the subscriober's port number
* @return Port number
*/
int
Subscriber::getPort()
{
return snd_seq_query_subscribe_get_port(m_Info);
}
/**
* Gets the subscriber's root address
* @return Pointer to the ALSA client/port address
*/
const snd_seq_addr_t*
Subscriber::getRoot()
{
return snd_seq_query_subscribe_get_root(m_Info);
}
/**
* Gets the subscription type (read or write).
*
* - SND_SEQ_QUERY_SUBS_READ: read subscriptions
* - SND_SEQ_QUERY_SUBS_WRITE: write subscriptions
*
* @return Subscription type
*/
snd_seq_query_subs_type_t
Subscriber::getType()
{
return snd_seq_query_subscribe_get_type(m_Info);
}
/**
* Gets the index of the subscriber container
* @return Index of the subscriber
*/
int
Subscriber::getIndex()
{
return snd_seq_query_subscribe_get_index(m_Info);
}
/**
* Gets the number of subscribers returned by a query operation
* @return Number of subscribers
*/
int
Subscriber::getNumSubs()
{
return snd_seq_query_subscribe_get_num_subs(m_Info);
}
/**
* Gets the subscriber's address
* @return Pointer to the ALSA address record
*/
const snd_seq_addr_t*
Subscriber::getAddr()
{
return snd_seq_query_subscribe_get_addr(m_Info);
}
/**
* Gets the subscriber's queue number
* @return Queue number
*/
int
Subscriber::getQueue()
{
return snd_seq_query_subscribe_get_queue(m_Info);
}
/**
* Gets the subscriber's exclusive flag
* @return Exclusive flag
*/
bool
Subscriber::getExclusive()
{
return (snd_seq_query_subscribe_get_exclusive(m_Info) != 0);
}
/**
* Gets the susbcriber's time-update flag
* @return Time update flag
*/
bool
Subscriber::getTimeUpdate()
{
return (snd_seq_query_subscribe_get_time_update(m_Info) != 0);
}
/**
* Gets the subscriber's time real time-stamp flag
* @return Time real flag
*/
bool
Subscriber::getTimeReal()
{
return (snd_seq_query_subscribe_get_time_real(m_Info) != 0);
}
/**
* Sets the subscriber's client number
* @param client Client number
*/
void
Subscriber::setClient(int client)
{
snd_seq_query_subscribe_set_client(m_Info, client);
}
/**
* Sets the subscriber's port number
* @param port Port number
*/
void
Subscriber::setPort(int port)
{
snd_seq_query_subscribe_set_port(m_Info, port);
}
/**
* Sets the subscriber's root address
* @param addr Pointer to the root ALSA address record
*/
void
Subscriber::setRoot(snd_seq_addr_t* addr)
{
snd_seq_query_subscribe_set_root(m_Info, addr);
}
/**
* Sets the subscription type
*
* - SND_SEQ_QUERY_SUBS_READ: read subscriptions
* - SND_SEQ_QUERY_SUBS_WRITE: write subscriptions
*
* @param type Subscription type
*/
void
Subscriber::setType(snd_seq_query_subs_type_t type)
{
snd_seq_query_subscribe_set_type(m_Info, type);
}
/**
* Sets the index of the subscriber
* @param index Subscriber index
*/
void
Subscriber::setIndex(int index)
{
snd_seq_query_subscribe_set_index(m_Info, index);
}
/**
* Gets the size of the ALSA query subscriber object
* @return Size of the ALSA object
*/
int
Subscriber::getSizeOfInfo() const
{
return snd_seq_query_subscribe_sizeof();
}
/**
* Default constructor
*/
Subscription::Subscription()
{
snd_seq_port_subscribe_malloc(&m_Info);
}
/**
* Copy constructor
* @param other Existing Subscription object reference
*/
Subscription::Subscription(const Subscription& other)
{
snd_seq_port_subscribe_malloc(&m_Info);
snd_seq_port_subscribe_copy(m_Info, other.m_Info);
}
/**
* Constructor
* @param other Pointer to an ALSA subscription object
*/
Subscription::Subscription(snd_seq_port_subscribe_t* other)
{
snd_seq_port_subscribe_malloc(&m_Info);
snd_seq_port_subscribe_copy(m_Info, other);
}
/**
* Constructor
* @param seq Pointer to a MIDI Client object
*/
Subscription::Subscription(MidiClient* seq)
{
snd_seq_port_subscribe_malloc(&m_Info);
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_port_subscription(seq->getHandle(), m_Info));
}
/**
* Destructor
*/
Subscription::~Subscription()
{
snd_seq_port_subscribe_free(m_Info);
}
/**
* Copy the current object
* @return Pointer to the new object
*/
Subscription*
Subscription::clone()
{
return new Subscription(m_Info);
}
/**
* Assignment operator
* @param other Existing subscription object reference
* @return This object
*/
Subscription&
Subscription::operator=(const Subscription& other)
{
if (this == &other)
return *this;
snd_seq_port_subscribe_copy(m_Info, other.m_Info);
return *this;
}
/**
* Gets the sender address of the subscription (MIDI OUT port)
* @return Pointer to the sender ALSA address record
*/
const snd_seq_addr_t*
Subscription::getSender()
{
return snd_seq_port_subscribe_get_sender(m_Info);
}
/**
* Gets the destination address of the subscription (MIDI IN port)
* @return Pointer to the destination ALSA address record
*/
const snd_seq_addr_t*
Subscription::getDest()
{
return snd_seq_port_subscribe_get_dest(m_Info);
}
/**
* Gets the susbcription's queue number
* @return Queue number
*/
int
Subscription::getQueue()
{
return snd_seq_port_subscribe_get_queue(m_Info);
}
/**
* Gets the subscription's exclusive flag
* @return Exclusive flag
*/
bool
Subscription::getExclusive()
{
return (snd_seq_port_subscribe_get_exclusive(m_Info) != 0);
}
/**
* Gets the susbcription's time-update flag
* @return Time-update flag
*/
bool
Subscription::getTimeUpdate()
{
return (snd_seq_port_subscribe_get_time_update(m_Info) != 0);
}
/**
* Gets the susbcription's time-real (time-stamping) flag
* @return Time real flag
*/
bool
Subscription::getTimeReal()
{
return (snd_seq_port_subscribe_get_time_real(m_Info) != 0);
}
/**
* Sets the Subscription's sender (MIDI OUT) port
* @param addr Pointer to the sender ALSA address record
*/
void
Subscription::setSender(const snd_seq_addr_t* addr)
{
snd_seq_port_subscribe_set_sender(m_Info, addr);
}
/**
* Sets the Subscription's destination (MIDI IN) port
* @param addr Pointer to the destination ALSA address record
*/
void
Subscription::setDest(const snd_seq_addr_t* addr)
{
snd_seq_port_subscribe_set_dest(m_Info, addr);
}
/**
* Sets the Subscription's Queue number
* @param q Queue number
*/
void
Subscription::setQueue(int q)
{
snd_seq_port_subscribe_set_queue(m_Info, q);
}
/**
* Sets the subscription's exclusive flag
* @param val Exclusive flag
*/
void
Subscription::setExclusive(bool val)
{
snd_seq_port_subscribe_set_exclusive(m_Info, val?1:0);
}
/**
* Sets the susbcription's time-update flag
* @param val Time update flag
*/
void
Subscription::setTimeUpdate(bool val)
{
snd_seq_port_subscribe_set_time_update(m_Info, val?1:0);
}
/**
* Sets the subscription's time real (time-stamping) flag
* @param val Time real flag
*/
void
Subscription::setTimeReal(bool val)
{
snd_seq_port_subscribe_set_time_real(m_Info, val?1:0);
}
/**
* Sets the Subscription's sender (MIDI OUT) port
* @param client Client number
* @param port Port number
*/
void
Subscription::setSender(unsigned char client, unsigned char port)
{
snd_seq_addr_t addr;
addr.client = client;
addr.port = port;
setSender(&addr);
}
/**
* Sets the Subscription's destination (MIDI IN) port
* @param client Client number
* @param port Port number
*/
void
Subscription::setDest(unsigned char client, unsigned char port)
{
snd_seq_addr_t addr;
addr.client = client;
addr.port = port;
setDest(&addr);
}
/**
* Performs the subscription in the ALSA sequencer subsystem.
* Neither the sender nor the destination ports need to belong to the
* same MidiClient instance performing the subscription.
* @param seq MidiClient instance pointer
*/
void
Subscription::subscribe(MidiClient* seq)
{
if ((m_Info == nullptr) || (seq == nullptr) || !(seq->isOpened()))
{
return;
}
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_subscribe_port(seq->getHandle(), m_Info));
}
/**
* Breaks the subscription in the ALSA sequencer subsystem.
* Neither the sender nor the destination ports need to belong to the
* same MidiClient instance breaking the subscription.
* @param seq MidiClient instance pointer
*/
void
Subscription::unsubscribe(MidiClient* seq)
{
if ((m_Info == nullptr) || (seq == nullptr) || !(seq->isOpened()))
{
return;
}
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_unsubscribe_port(seq->getHandle(), m_Info));
}
/**
* Gets the size of the ALSA subscription object
* @return Size of the ALSA object
*/
int
Subscription::getSizeOfInfo() const
{
return snd_seq_port_subscribe_sizeof();
}
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/alsa/alsaevent.cpp 0000644 0001750 0001750 00000072565 14541630232 017624 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include "errorcheck.h"
#include
/**
* @file alsaevent.cpp
* Implementation of classes managing ALSA Sequencer events.
*/
/**
* @class QEvent
* The QEvent class is the base class of all event classes.
* @see https://doc.qt.io/qt-5/qevent.html
*/
namespace drumstick { namespace ALSA {
/**
* @addtogroup ALSAEvent
* @{
*
* MIDI Events are messages transmitted between MIDI devices or applications.
*
* Classes:
*
* SequencerEvent: Base class for the event's hierarchy.
*
* ChannelEvent: Base class for the events having a Channel property.
*
* KeyEvent: Base class for the events having Key and Velocity properties.
*
* NoteEvent: Class representing a note event with duration.
*
* NoteOnEvent: Event representing a note-on MIDI event.
*
* NoteOffEvent: Event representing a note-off MIDI event.
*
* KeyPressEvent: Event representing a MIDI key pressure, or polyphonic after-touch event.
*
* ControllerEvent: Event representing a MIDI control change event.
*
* ProgramChangeEvent: Event representing a MIDI program change event.
*
* PitchBendEvent: Event representing a MIDI bender, or pitch wheel event.
*
* ChanPressEvent: Event representing a MIDI channel pressure or after-touch event.
*
* VariableEvent: Base class for variable length events.
*
* SysExEvent: Event representing a MIDI system exclusive event.
*
* TextEvent: Event representing a SMF text event.
*
* SystemEvent: Generic event.
*
* QueueControlEvent: ALSA Event representing a queue control command.
*
* ValueEvent: Generic event having a value property.
*
* TempoEvent: ALSA Event representing a tempo change for an ALSA queue.
*
* SubscriptionEvent: ALSA Event representing a subscription between two ALSA clients and ports.
*
* ClientEvent: ALSA Event representing a change on some ALSA sequencer client.
*
* PortEvent: ALSA Event representing a change on some ALSA sequencer port.
*
* RemoveEvents: Auxiliary class to remove events from an ALSA queue.
*
* MidiCodec: Auxiliary class to translate between raw MIDI streams and ALSA events.
*
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_event.html
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_events.html
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_ev_type.html
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___m_i_d_i___event.html
* @}
*/
/**
* Default constructor.
*/
SequencerEvent::SequencerEvent() : QEvent(SequencerEventType)
{
snd_seq_ev_clear( &m_event );
}
/**
* Constructor from an ALSA event record
* @param event ALSA event record
*/
SequencerEvent::SequencerEvent(const snd_seq_event_t* event) : QEvent(SequencerEventType)
{
snd_seq_ev_clear( &m_event );
m_event = *event;
}
/**
* Copy constructor
* @param other A SequencerEvent object reference
*/
SequencerEvent::SequencerEvent(const SequencerEvent& other) : QEvent(SequencerEventType)
{
snd_seq_ev_clear( &m_event );
m_event = other.m_event;
}
/**
* Assignment operator
* @param other A SequencerEvent object reference
* @return This object
*/
SequencerEvent&
SequencerEvent::operator=(const SequencerEvent& other)
{
m_event = other.m_event;
return *this;
}
/**
* Checks if the event's type is a subscription.
* @param event A SequencerEvent object pointer
* @return True if the event has a subscribe/unsubscribe type.
*/
bool
SequencerEvent::isSubscription(const SequencerEvent* event)
{
snd_seq_event_type_t te = event->getSequencerType();
return ( te == SND_SEQ_EVENT_PORT_SUBSCRIBED ||
te == SND_SEQ_EVENT_PORT_UNSUBSCRIBED );
}
/**
* Checks if the event's type is of type port.
* @param event A SequencerEvent object pointer
* @return True if the event has a port start/exit/change type.
*/
bool
SequencerEvent::isPort(const SequencerEvent* event)
{
snd_seq_event_type_t te = event->getSequencerType();
return ( te == SND_SEQ_EVENT_PORT_START ||
te == SND_SEQ_EVENT_PORT_EXIT ||
te == SND_SEQ_EVENT_PORT_CHANGE );
}
/**
* Checks if the event's type is of type client.
* @param event A SequencerEvent object pointer
* @return True if the event has a client start/exit/change type.
*/
bool
SequencerEvent::isClient(const SequencerEvent* event)
{
snd_seq_event_type_t te = event->getSequencerType();
return ( te == SND_SEQ_EVENT_CLIENT_START ||
te == SND_SEQ_EVENT_CLIENT_EXIT ||
te == SND_SEQ_EVENT_CLIENT_CHANGE );
}
/**
* Checks if the event's type is of type connection change.
* @param event A SequencerEvent object pointer
* @return True if the event has a client/port/subscription type.
*/
bool
SequencerEvent::isConnectionChange(const SequencerEvent* event)
{
snd_seq_event_type_t te = event->getSequencerType();
return ( te == SND_SEQ_EVENT_PORT_START ||
te == SND_SEQ_EVENT_PORT_EXIT ||
te == SND_SEQ_EVENT_PORT_CHANGE ||
te == SND_SEQ_EVENT_CLIENT_START ||
te == SND_SEQ_EVENT_CLIENT_EXIT ||
te == SND_SEQ_EVENT_CLIENT_CHANGE ||
te == SND_SEQ_EVENT_PORT_SUBSCRIBED ||
te == SND_SEQ_EVENT_PORT_UNSUBSCRIBED );
}
/**
* Checks if the event's type is a Channel Voice message.
* @param event A SequencerEvent object pointer
* @return True if the event is a channel voice message.
* @since 0.2.0
*/
bool
SequencerEvent::isChannel(const SequencerEvent* event)
{
snd_seq_event_type_t te = event->getSequencerType();
return ( te == SND_SEQ_EVENT_NOTEOFF ||
te == SND_SEQ_EVENT_NOTEON ||
te == SND_SEQ_EVENT_NOTE ||
te == SND_SEQ_EVENT_KEYPRESS ||
te == SND_SEQ_EVENT_CONTROLLER ||
te == SND_SEQ_EVENT_CONTROL14 ||
te == SND_SEQ_EVENT_PGMCHANGE ||
te == SND_SEQ_EVENT_CHANPRESS ||
te == SND_SEQ_EVENT_PITCHBEND );
}
/**
* Sets the event's ALSA sequencer type
* @param eventType The ALSA sequencer type
*/
void SequencerEvent::setSequencerType(const snd_seq_event_type_t eventType)
{
m_event.type = eventType;
}
/**
* Sets the client:port destination of the event.
* @param client The destination's client ID
* @param port The destination port ID
* @see setSubscribers()
*/
void SequencerEvent::setDestination(const unsigned char client, const unsigned char port)
{
snd_seq_ev_set_dest(&m_event, client, port);
}
/**
* Sets the event's source port ID
* @param port The source port ID
* @see getSourceClient(), getSourcePort()
*/
void SequencerEvent::setSource(const unsigned char port)
{
snd_seq_ev_set_source(&m_event, port);
}
/**
* Sets the event's destination to be all the subscribers of the source port.
*/
void SequencerEvent::setSubscribers()
{
snd_seq_ev_set_subs(&m_event);
}
/**
* Sets the event's destination to be all queues/clients/ports/channels.
*/
void SequencerEvent::setBroadcast()
{
snd_seq_ev_set_broadcast(&m_event);
}
/**
* Sets the event to be immediately delivered, not queued/scheduled.
* @see scheduleTick(), scheduleReal()
*/
void SequencerEvent::setDirect()
{
snd_seq_ev_set_direct(&m_event);
}
/**
* Sets the event to be scheduled in musical time (ticks) units.
* @param queue The queue number to be used.
* @param tick The time in ticks.
* @param relative Use relative (to the current) time instead of absolute time.
*/
void SequencerEvent::scheduleTick(int queue, int tick, bool relative)
{
snd_seq_ev_schedule_tick(&m_event, queue, relative, tick);
}
/**
* Sets the event to be scheduled in real (clock) time units.
* @param queue The queue number to be used.
* @param secs The time in whole seconds.
* @param nanos The nanoseconds to be added.
* @param relative Use relative (to the current) time instead of absolute time.
*/
void SequencerEvent::scheduleReal(int queue, ulong secs, ulong nanos, bool relative)
{
snd_seq_real_time_t rtime;
rtime.tv_sec = secs;
rtime.tv_nsec = nanos;
snd_seq_ev_schedule_real(&m_event, queue, relative, &rtime);
}
/**
* Sets the priority of the event. This is used in case of several events share
* the same scheduling time.
*
* @param high Mark the event as a high priority one.
*/
void SequencerEvent::setPriority(const bool high)
{
snd_seq_ev_set_priority(&m_event, high);
}
/**
* Sets the event's tag. This attribute is any arbitrary number, not used by
* the ALSA library. Range limited to 0 thru 255.
* @param aTag A tag number.
*/
void SequencerEvent::setTag(const unsigned char aTag)
{
#if SND_LIB_VERSION > 0x010008
snd_seq_ev_set_tag(&m_event, aTag);
#else
m_event.tag = aTag;
#endif
}
/**
* Gets an event's raw 32 bits parameter.
* @param n The parameter index, between 0 and 2.
* @return The parameter's value.
* @see setRaw32()
*/
unsigned int SequencerEvent::getRaw32(const unsigned int n) const
{
if (n < 3) return m_event.data.raw32.d[n];
return 0;
}
/**
* Sets an event's raw 32 bits parameter.
* @param n The parameter index, between 0 and 2.
* @param value The parameter's value.
*/
void SequencerEvent::setRaw32(const unsigned int n, const unsigned int value)
{
if (n < 3) m_event.data.raw32.d[n] = value;
}
/**
* Gets an event's raw 8 bits parameter.
* @param n The parameter index, between 0 and 11.
* @return The parameter's value.
* @see setRaw8()
*/
unsigned char SequencerEvent::getRaw8(const unsigned int n) const
{
if (n < 12) return m_event.data.raw8.d[n];
return 0;
}
/**
* Sets an event's raw 8 bits parameter.
* @param n The parameter index, between 0 and 11.
* @param value The parameter's value.
*/
void SequencerEvent::setRaw8(const unsigned int n, const unsigned char value)
{
if (n < 12) m_event.data.raw8.d[n] = value;
}
/**
* Releases the event record.
* @deprecated the event record is not allocated, so you don't have to call this function
*/
void SequencerEvent::free()
{
snd_seq_free_event(&m_event);
}
/**
* Gets the encoded length of the event record.
* @return The encoded length.
*/
int SequencerEvent::getEncodedLength()
{
return snd_seq_event_length(&m_event);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
SequencerEvent* SequencerEvent::clone() const
{
return new SequencerEvent(&m_event);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
ChannelEvent* ChannelEvent::clone() const
{
return new ChannelEvent(&m_event);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
KeyEvent* KeyEvent::clone() const
{
return new KeyEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param key MIDI note.
* @param vel Note velocity.
* @param dur Note duration.
*/
NoteEvent::NoteEvent(const int ch, const int key, const int vel, const int dur) : KeyEvent()
{
snd_seq_ev_set_note(&m_event, ch, key, vel, dur);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
NoteEvent* NoteEvent::clone() const
{
return new NoteEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param key MIDI note.
* @param vel Note velocity.
*/
NoteOnEvent::NoteOnEvent(int ch, int key, int vel) : KeyEvent()
{
snd_seq_ev_set_noteon(&m_event, ch, key, vel);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
NoteOnEvent* NoteOnEvent::clone() const
{
return new NoteOnEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param key MIDI note.
* @param vel Note velocity.
*/
NoteOffEvent::NoteOffEvent(int ch, int key, int vel) : KeyEvent()
{
snd_seq_ev_set_noteoff(&m_event, ch, key, vel);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
NoteOffEvent* NoteOffEvent::clone() const
{
return new NoteOffEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param key MIDI note.
* @param vel Note velocity.
*/
KeyPressEvent::KeyPressEvent(int ch, int key, int vel) : KeyEvent()
{
snd_seq_ev_set_keypress(&m_event, ch, key, vel);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
KeyPressEvent* KeyPressEvent::clone() const
{
return new KeyPressEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param cc MIDI Controller number.
* @param val Controller value.
*/
ControllerEvent::ControllerEvent(int ch, int cc, int val) : ChannelEvent()
{
snd_seq_ev_set_controller(&m_event, ch, cc, val);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
ControllerEvent* ControllerEvent::clone() const
{
return new ControllerEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param val MIDI Program number.
*/
ProgramChangeEvent::ProgramChangeEvent(int ch, int val) : ChannelEvent()
{
snd_seq_ev_set_pgmchange(&m_event, ch, val);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
ProgramChangeEvent* ProgramChangeEvent::clone() const
{
return new ProgramChangeEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param val Pitch Bend value. Zero centered from -8192 to 8191.
*/
PitchBendEvent::PitchBendEvent(int ch, int val) : ChannelEvent()
{
snd_seq_ev_set_pitchbend(&m_event, ch, val);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
PitchBendEvent* PitchBendEvent::clone() const
{
return new PitchBendEvent(&m_event);
}
/**
* Constructor using proper attribute values.
* @param ch MIDI Channel.
* @param val Aftertouch value.
*/
ChanPressEvent::ChanPressEvent(int ch, int val) : ChannelEvent()
{
snd_seq_ev_set_chanpress(&m_event, ch, val);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
ChanPressEvent* ChanPressEvent::clone() const
{
return new ChanPressEvent(&m_event);
}
/**
* Default constructor.
*/
VariableEvent::VariableEvent()
: SequencerEvent()
{
m_data.clear();
snd_seq_ev_set_variable ( &m_event, m_data.size(), m_data.data() );
}
/**
* Constructor from an ALSA event record.
* @param event ALSA event record.
*/
VariableEvent::VariableEvent(const snd_seq_event_t* event)
: SequencerEvent(event)
{
m_data = QByteArray((char *) event->data.ext.ptr,
event->data.ext.len);
snd_seq_ev_set_variable ( &m_event, m_data.size(), m_data.data() );
}
/**
* Constructor from an arbitrary data array.
* @param data A data byte array.
*/
VariableEvent::VariableEvent(const QByteArray& data)
: SequencerEvent()
{
m_data = data;
snd_seq_ev_set_variable ( &m_event, m_data.size(), m_data.data() );
}
/**
* Copy constructor.
* @param other Another VariableEvent instance.
s */
VariableEvent::VariableEvent(const VariableEvent& other)
: SequencerEvent(other)
{
m_data = other.m_data;
snd_seq_ev_set_variable ( &m_event, m_data.size(), m_data.data() );
}
/**
* Constructor from a data pointer.
* @param datalen Length of the data.
* @param dataptr Pointer the data.
*/
VariableEvent::VariableEvent(const unsigned int datalen, char* dataptr)
: SequencerEvent()
{
m_data = QByteArray(dataptr, datalen);
snd_seq_ev_set_variable( &m_event, m_data.size(), m_data.data() );
}
/**
* Assignment operator.
* @param other Another VariableEvent object reference
* @return Pointer to this object
*/
VariableEvent& VariableEvent::operator=(const VariableEvent& other)
{
m_event = other.m_event;
m_data = other.m_data;
snd_seq_ev_set_variable ( &m_event, m_data.size(), m_data.data() );
return *this;
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
VariableEvent* VariableEvent::clone() const
{
return new VariableEvent(&m_event);
}
/**
* Default constructor.
*/
SysExEvent::SysExEvent()
: VariableEvent()
{
snd_seq_ev_set_sysex( &m_event, m_data.size(), m_data.data() );
}
/**
* Constructor from an ALSA event record.
* @param event ALSA event record.
*/
SysExEvent::SysExEvent(const snd_seq_event_t* event)
: VariableEvent(event)
{
snd_seq_ev_set_sysex( &m_event, m_data.size(), m_data.data() );
}
/**
* Constructor from a data array.
* @param data A data byte array.
*/
SysExEvent::SysExEvent(const QByteArray& data)
: VariableEvent(data)
{
snd_seq_ev_set_sysex( &m_event, m_data.size(), m_data.data() );
}
/**
* Copy constructor.
* @param other Another SysExEvent object reference.
*/
SysExEvent::SysExEvent(const SysExEvent& other)
: VariableEvent(other)
{
snd_seq_ev_set_sysex( &m_event, m_data.size(), m_data.data() );
}
/**
* Constructor taking a data pointer and length
* @param datalen Data length
* @param dataptr Data pointer
*/
SysExEvent::SysExEvent(const unsigned int datalen, char* dataptr)
: VariableEvent( datalen, dataptr )
{
snd_seq_ev_set_sysex( &m_event, m_data.size(), m_data.data() );
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
SysExEvent* SysExEvent::clone() const
{
return new SysExEvent(&m_event);
}
/**
* Assignment operator.
* @param other Another SysExEvent object reference
* @return pointer to this object
*/
SysExEvent &SysExEvent::operator=(const SysExEvent &other)
{
m_event = other.m_event;
m_data = other.m_data;
snd_seq_ev_set_sysex(&m_event, m_data.size(), m_data.data());
return *this;
}
/**
* Default constructor
*/
TextEvent::TextEvent()
: VariableEvent(), m_textType(1)
{
setSequencerType(SND_SEQ_EVENT_USR_VAR0);
}
/**
* Constructor from an ALSA sequencer record.
* @param event ALSA sequencer record.
*/
TextEvent::TextEvent(const snd_seq_event_t* event)
: VariableEvent(event), m_textType(1)
{
setSequencerType(SND_SEQ_EVENT_USR_VAR0);
}
/**
* Constructor from a given string
* @param text The event's text
* @param textType The SMF text type
*/
TextEvent::TextEvent(const QString& text, const int textType)
: VariableEvent(text.toUtf8()), m_textType(textType)
{
setSequencerType(SND_SEQ_EVENT_USR_VAR0);
}
/**
* Copy constructor
* @param other An existing TextEvent object reference
*/
TextEvent::TextEvent(const TextEvent& other)
: VariableEvent(other)
{
setSequencerType(SND_SEQ_EVENT_USR_VAR0);
m_textType = other.getTextType();
}
/**
* Constructor from a data pointer and length
* @param datalen Data length
* @param dataptr Data pointer
*/
TextEvent::TextEvent(const unsigned int datalen, char* dataptr)
: VariableEvent(datalen, dataptr), m_textType(1)
{
setSequencerType(SND_SEQ_EVENT_USR_VAR0);
}
/**
* Gets the event's text content.
* @return The text content.
*/
QString TextEvent::getText() const
{
return QString::fromUtf8(m_data.data(), m_data.size());
}
/**
* Gets the event's SMF text type.
* @return The SMF text type.
*/
int TextEvent::getTextType() const
{
return m_textType;
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
TextEvent* TextEvent::clone() const
{
return new TextEvent(&m_event);
}
/**
* Assignment operator.
* @param other Another TextEvent object reference
* @return pointer to this object
*/
TextEvent &TextEvent::operator=(const TextEvent &other)
{
m_event = other.m_event;
m_data = other.m_data;
m_textType = other.getTextType();
snd_seq_ev_set_variable(&m_event, m_data.size(), m_data.data());
setSequencerType(SND_SEQ_EVENT_USR_VAR0);
return *this;
}
/**
* Constructor
* @param type The event's type
*/
SystemEvent::SystemEvent(const snd_seq_event_type_t type) : SequencerEvent()
{
snd_seq_ev_set_fixed(&m_event);
setSequencerType(type);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
SystemEvent* SystemEvent::clone() const
{
return new SystemEvent(&m_event);
}
/**
* Constructor
* @param type Event type
* @param queue Queue number
* @param value Value
*/
QueueControlEvent::QueueControlEvent(snd_seq_event_type_t type, int queue, int value)
: SequencerEvent()
{
snd_seq_ev_set_queue_control(&m_event, type, queue, value);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
QueueControlEvent* QueueControlEvent::clone() const
{
return new QueueControlEvent(&m_event);
}
/**
* Constructor
* @param type The event's type
* @param val Value
*/
ValueEvent::ValueEvent(const snd_seq_event_type_t type, int val) : SequencerEvent()
{
snd_seq_ev_set_fixed(&m_event);
setSequencerType(type);
setValue(val);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
ValueEvent* ValueEvent::clone() const
{
return new ValueEvent(&m_event);
}
/**
* Constructor
* @param queue Queue number.
* @param tempo Tempo value in microseconds per quarter note.
*/
TempoEvent::TempoEvent(int queue, int tempo) : QueueControlEvent()
{
snd_seq_ev_set_queue_tempo(&m_event, queue, tempo);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
TempoEvent* TempoEvent::clone() const
{
return new TempoEvent(&m_event);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
ClientEvent* ClientEvent::clone() const
{
return new ClientEvent(&m_event);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
PortEvent* PortEvent::clone() const
{
return new PortEvent(&m_event);
}
/**
* Clone this object returning a pointer to the new object
* @return pointer to the new object
*/
SubscriptionEvent* SubscriptionEvent::clone() const
{
return new SubscriptionEvent(&m_event);
}
/**
* Default constructor.
*/
RemoveEvents::RemoveEvents()
{
snd_seq_remove_events_malloc(&m_Info);
}
/**
* Copy constructor.
* @param other An existing RemoveEvents object reference.
*/
RemoveEvents::RemoveEvents(const RemoveEvents& other)
{
snd_seq_remove_events_malloc(&m_Info);
snd_seq_remove_events_copy(m_Info, other.m_Info);
}
/**
* Constructor from an ALSA remove events object pointer.
* @param other An ALSA remove events object pointer.
*/
RemoveEvents::RemoveEvents(snd_seq_remove_events_t* other)
{
snd_seq_remove_events_malloc(&m_Info);
snd_seq_remove_events_copy(m_Info, other);
}
/**
* Destructor.
*/
RemoveEvents::~RemoveEvents()
{
snd_seq_remove_events_free(m_Info);
}
/**
* Create a new object copied from this object and return a pointer to the copy.
* @return A pointer to the new object.
*/
RemoveEvents*
RemoveEvents::clone()
{
return new RemoveEvents(m_Info);
}
/**
* Assignment operator.
* @param other An existing RemoveEvents object reference.
* @return This object.
*/
RemoveEvents&
RemoveEvents::operator=(const RemoveEvents& other)
{
if (this == &other)
return *this;
snd_seq_remove_events_copy(m_Info, other.m_Info);
return *this;
}
/**
* Gets the allocated size of the ALSA remove events object.
* @return The size of the ALSA remove events object.
*/
int
RemoveEvents::getSizeOfInfo() const
{
return snd_seq_remove_events_sizeof();
}
/**
* Gets the MIDI channel.
* @return The MIDI channel.
* @see setChannel()
*/
int
RemoveEvents::getChannel()
{
return snd_seq_remove_events_get_channel(m_Info);
}
/**
* Gets the condition.
* @return The condition.
* @see setCondition()
*/
unsigned int
RemoveEvents::getCondition()
{
return snd_seq_remove_events_get_condition(m_Info);
}
/**
* Gets the destination.
* @return The destination record pointer.
* @see setDest()
*/
const snd_seq_addr_t*
RemoveEvents::getDest()
{
return snd_seq_remove_events_get_dest(m_Info);
}
/**
* Gets the event type.
* @return The event type.
* @see setEventType()
*/
int
RemoveEvents::getEventType()
{
return snd_seq_remove_events_get_event_type(m_Info);
}
/**
* Gets the queue number.
* @return The queue number.
* @see setQueue()
*/
int
RemoveEvents::getQueue()
{
return snd_seq_remove_events_get_queue(m_Info);
}
/**
* Gets the numeric tag.
* @return The numeric tag.
* @see setTag()
*/
int
RemoveEvents::getTag()
{
return snd_seq_remove_events_get_tag(m_Info);
}
/**
* Gets the timestamp.
* @return The timestamp.
* @see setTime()
*/
const snd_seq_timestamp_t*
RemoveEvents::getTime()
{
return snd_seq_remove_events_get_time(m_Info);
}
/**
* Gets the MIDI channel.
* @param chan The MIDI channel.
* @see getChannel()
*/
void
RemoveEvents::setChannel(int chan)
{
snd_seq_remove_events_set_channel(m_Info, chan);
}
/**
* Sets the flags of the conditional event's removal. This condition is a
* bitmap of the combination (OR) the following auto-described flags:
*
* - SND_SEQ_REMOVE_INPUT
* - SND_SEQ_REMOVE_OUTPUT
* - SND_SEQ_REMOVE_DEST
* - SND_SEQ_REMOVE_DEST_CHANNEL
* - SND_SEQ_REMOVE_TIME_BEFORE
* - SND_SEQ_REMOVE_TIME_AFTER
* - SND_SEQ_REMOVE_TIME_TICK
* - SND_SEQ_REMOVE_EVENT_TYPE
* - SND_SEQ_REMOVE_IGNORE_OFF
* - SND_SEQ_REMOVE_TAG_MATCH
*
* @param cond The condition bitmap.
* @see getCondition()
*/
void
RemoveEvents::setCondition(unsigned int cond)
{
snd_seq_remove_events_set_condition(m_Info, cond);
}
/**
* Set the destination address.
* @param dest A pointer to the destination address record.
* @see getDest()
*/
void
RemoveEvents::setDest(const snd_seq_addr_t* dest)
{
snd_seq_remove_events_set_dest(m_Info, dest);
}
/**
* Sets the event type.
* @param type The event type.
* @see getEventType()
*/
void
RemoveEvents::setEventType(int type)
{
snd_seq_remove_events_set_event_type(m_Info, type);
}
/**
* Sets the queue number.
* @param queue The queue number.
* @see getQueue()
*/
void
RemoveEvents::setQueue(int queue)
{
snd_seq_remove_events_set_queue(m_Info, queue);
}
/**
* Sets the numeric tag.
* @param tag The numeric tag.
* @see getTag()
*/
void
RemoveEvents::setTag(int tag)
{
snd_seq_remove_events_set_tag(m_Info, tag);
}
/**
* Sets the timestamp.
* @param time A pointer to the timestamp record.
* @see getTime()
*/
void
RemoveEvents::setTime(const snd_seq_timestamp_t* time)
{
snd_seq_remove_events_set_time(m_Info, time);
}
/**
* MidiCodec constructor
* @param bufsize The buffer size of the CODEC
* @param parent The optional parent object
*/
MidiCodec::MidiCodec( int bufsize, QObject* parent ) : QObject(parent)
{
DRUMSTICK_ALSA_CHECK_ERROR(snd_midi_event_new(bufsize, &m_Info));
}
/**
* Destructor
*/
MidiCodec::~MidiCodec()
{
snd_midi_event_free(m_Info);
}
/**
* CODEC initialization.
*/
void
MidiCodec::init()
{
snd_midi_event_init(m_Info);
}
/**
* Decode from event to bytes.
* @param buf A buffer to get the results
* @param count Available bytes in MIDI byte stream
* @param ev The input event
* @return The number of written bytes if success.
*/
long
MidiCodec::decode(unsigned char *buf,
long count,
const snd_seq_event_t *ev)
{
return DRUMSTICK_ALSA_CHECK_WARNING(snd_midi_event_decode(m_Info, buf, count, ev));
}
/**
* Encode from byte stream.
* @param buf MIDI byte stream
* @param count Bytes of MIDI byte stream to encode
* @param ev Result - sequencer event
* @return Number of written bytes if success.
*/
long
MidiCodec::encode(const unsigned char *buf,
long count,
snd_seq_event_t *ev)
{
return DRUMSTICK_ALSA_CHECK_WARNING(snd_midi_event_encode(m_Info, buf, count, ev));
}
/**
* Read one byte and encode to sequencer event if finished.
* @param c A byte of MIDI stream
* @param ev Result - sequencer event
* @return 1 - sequencer event is completed, 0 - next byte is required for completion, otherwise a negative error code
*/
long
MidiCodec::encode(int c,
snd_seq_event_t *ev)
{
return DRUMSTICK_ALSA_CHECK_WARNING(snd_midi_event_encode_byte(m_Info, c, ev));
}
/**
* Enable MIDI running status (command merge)
* @param enable True to enable, false to disable.
*/
void
MidiCodec::enableRunningStatus(bool enable)
{
snd_midi_event_no_status(m_Info, enable ? 0 : 1);
}
/**
* Reset MIDI decode parser.
*/
void
MidiCodec::resetDecoder()
{
snd_midi_event_reset_decode(m_Info);
}
/**
* Reset MIDI encode parser.
*/
void
MidiCodec::resetEncoder()
{
snd_midi_event_reset_encode(m_Info);
}
/**
* Resize the CODEC buffer
* @param bufsize New buffer size.
*/
void
MidiCodec::resizeBuffer(int bufsize)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_midi_event_resize_buffer(m_Info, bufsize));
}
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/alsa/CMakeLists.txt 0000644 0001750 0001750 00000007712 14541630232 017666 0 ustar pedro pedro #[===========================================================================[
MIDI C++ Library
Copyright (C) 2005-2023 Pedro Lopez-Cabanillas
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 3 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, see .
#]===========================================================================]
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(drumstick-alsa_QTOBJ_SRCS
../include/drumstick/alsaclient.h
../include/drumstick/alsaevent.h
../include/drumstick/alsaport.h
../include/drumstick/alsaqueue.h
../include/drumstick/alsatimer.h
../include/drumstick/playthread.h
)
set(drumstick-alsa_HEADERS
../include/drumstick/alsaclient.h
../include/drumstick/alsaevent.h
../include/drumstick/alsaport.h
../include/drumstick/alsaqueue.h
../include/drumstick/alsatimer.h
../include/drumstick/playthread.h
../include/drumstick/sequencererror.h
../include/drumstick/subscription.h
../include/drumstick/macros.h
)
set(drumstick-alsa_SRCS
alsaclient.cpp
alsaevent.cpp
alsaport.cpp
alsaqueue.cpp
alsatimer.cpp
playthread.cpp
sequencererror.cpp
subscription.cpp
)
if (QT_VERSION VERSION_LESS 5.15.0)
qt5_wrap_cpp(drumstick-alsa_MOC_SRCS ${drumstick-alsa_QTOBJ_SRCS})
else()
qt_wrap_cpp(drumstick-alsa_MOC_SRCS ${drumstick-alsa_QTOBJ_SRCS})
endif()
add_library(drumstick-alsa
${drumstick-alsa_MOC_SRCS}
${drumstick-alsa_SRCS}
${drumstick-alsa_HEADERS}
)
add_library(Drumstick::ALSA ALIAS drumstick-alsa)
target_include_directories(drumstick-alsa PUBLIC
$
$
)
#message(STATUS "ALSA -- HAVE_DBUS: ${HAVE_DBUS}")
target_compile_definitions(drumstick-alsa PRIVATE
QT_NO_SIGNALS_SLOTS_KEYWORDS
$<$:RTKIT_SUPPORT>
)
target_link_libraries(drumstick-alsa PRIVATE
Qt${QT_VERSION_MAJOR}::Core
PkgConfig::ALSA
)
if(USE_DBUS)
target_link_libraries(drumstick-alsa PRIVATE
Qt${QT_VERSION_MAJOR}::DBus
)
endif()
if(STATIC_DRUMSTICK)
set_target_properties(drumstick-alsa PROPERTIES
STATIC_LIB "libdrumstick-alsa"
EXPORT_NAME ALSA
)
else()
set_target_properties(drumstick-alsa PROPERTIES
VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
SOVERSION ${PROJECT_VERSION_MAJOR}
EXPORT_NAME ALSA
)
endif()
install(TARGETS drumstick-alsa
EXPORT drumstick-alsa-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(FILES ${drumstick-alsa_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/drumstick)
install(EXPORT drumstick-alsa-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/drumstick
NAMESPACE Drumstick::
)
export(EXPORT drumstick-alsa-targets
NAMESPACE Drumstick::
FILE ${CMAKE_BINARY_DIR}/drumstick-alsa-targets.cmake
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file( ${CMAKE_BINARY_DIR}/drumstick-alsa-config-version.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_file( drumstick-alsa-config.cmake
${CMAKE_BINARY_DIR}/drumstick-alsa-config.cmake
@ONLY
)
install(FILES
${CMAKE_BINARY_DIR}/drumstick-alsa-config-version.cmake
${CMAKE_BINARY_DIR}/drumstick-alsa-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/drumstick
)
drumstick-2.9.0/library/alsa/alsaclient.cpp 0000644 0001750 0001750 00000202055 14541630232 017746 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include "errorcheck.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(RTKIT_SUPPORT)
#include
#include
#include
#include
#include
#endif
#include
#ifndef RLIMIT_RTTIME
#define RLIMIT_RTTIME 15
#endif
#ifndef SCHED_RESET_ON_FORK
#define SCHED_RESET_ON_FORK 0x40000000
#endif
#ifndef DEFAULT_INPUT_TIMEOUT
#define DEFAULT_INPUT_TIMEOUT 500
#endif
/**
* @file alsaclient.cpp
* Implementation of classes managing ALSA Sequencer clients
*/
/**
* @class QObject
* The QObject class is the base class of all Qt objects.
* @see https://doc.qt.io/qt-5/qobject.html
*/
/**
* @class QThread
* The QThread class provides platform-independent threads.
* @see https://doc.qt.io/qt-5/qthread.html
*/
namespace drumstick { namespace ALSA {
/**
* @addtogroup ALSAClient
* @{
*
* ALSA clients are any entities using ALSA sequencer services. A client
* may be an application or a device driver for an external MIDI port, like
* USB MIDI devices or the MIDI/game ports of some sound cards. This library
* allows to easily create applications managing ALSA clients.
*
* ALSA clients are also file descriptors representing a sequencer device,
* that must be opened before reading or writing MIDI events. When the client
* is opened, it is given some handle and a number identifying it to other
* clients in the system. You can also provide a name for it.
*
* Each ALSA sequencer client can have several ports attached. The ports can be
* readable or writable, and can be subscribed in pairs: one readable port to
* one writable port. The subscriptions can be made and queried by external
* applications, like "aconnect" or "qjackctl".
*
* SystemInfo is an auxiliary class to query several system capabilities.
*
* The PoolInfo class represents a container to query and change some values
* for the kernel memory pool assigned to an ALSA client.
*
* The ClientInfo class is another container to query and change properties of
* the MidiClient itself.
*
* The SequencerEventHandler abstract class is used to define an interface
* that other class can implement to receive sequencer events. It is one of the
* three methods of delivering input events offered by the library.
*
* @section EventInput Input
* MidiClient uses a separate thread to receive events from the ALSA sequencer.
* The input thread can be started and stopped using the methods
* MidiClient::startSequencerInput() and MidiClient::stopSequencerInput().
* It is necessary to have this thread in mind when using this library to read
* events. There are three delivering methods of input events:
*
* - A Callback method. To use this method, you must derive a class from
* SequencerEventHandler, overriding the method
* SequencerEventHandler::handleSequencerEvent() to provide your own event
* processing code. You must give a handler instance pointer to
* the client using MidiClient::setHandler().
* - Using QEvent listeners. To use this method, you must have one or more
* classes derived from QObject overriding the method QObject::customEvent().
* You must also use the method MidiClient::addListener() to add such objects
* to the client's listeners list, and MidiClient::setEventsEnabled().
* - The third method involves signals and slots. Whenever a sequencer event
* is received, a signal MidiClient::eventReceived() is emitted, that can be
* connected to your own supplied slot(s) to process it.
*
* The selected method depends only on your requirements and your preferences.
*
* - The Callback method is preferred for real-time usage because the handler
* receives the events without any delay, but at the same time you must
* avoid calling methods of any GUI widgets within the handler. Instead,
* you can create QEvents and call QObject::postEvent() to notify the GUI.
* - Inside QObject::eventReceiver() you can collect QEvents and call
* any method you want, but the events are not delivered in real-time. Instead,
* they are enqueued and dispatched by the main application's event loop.
* - The signals/slots method can be real-time or queued, depending on the
* last parameter of QObject::connect(). If it is Qt::DirectConnection, the signal
* is delivered in real-time, and the same rule about avoiding calls to any
* GUI widgets methods apply. If it is Qt::QueuedConnection, then the signal is
* enqueued using the application's event loop, and it is safe to call any GUI
* methods in this case.
*
* Whichever method you select, it excludes the other methods for the same
* program. A callback takes precedence over the others. If it is not set, then
* the events are sent if MidiClient::setEventsEnabled() is called.
* If neither a callback handler is set nor events are enabled, then the signal
* is emitted. In any case, the event pointer must be deleted by the receiver
* method.
*
* @see https://doc.qt.io/qt-5/threads-reentrancy.html
*
* @section EventOutput Output
*
* The methods to send a single event to the ALSA sequencer are:
*
* - MidiClient::output() using the library buffer, automatically flushed.
* - MidiClient::outputBuffer() using the library buffer. Not flushed automatically.
* - MidiClient::outputDirect() not using the library buffer.
*
* The two first methods usually require a call to MidiClient::drainOutput() to
* flush the ALSA library output buffer. The third one bypasses the buffer, and
* doesn't require the call to MidiClient::drainOutput(). Note that the buffer
* can be automatically drained by the first method when it becomes full.
*
* After being dispatched to the ALSA Sequencer, the events can be scheduled at
* some time in the future, or immediately. This depends on the following
* methods of the SequencerEvent class:
*
* - SequencerEvent::setDirect() not scheduled
* - SequencerEvent::scheduleTick() scheduled in musical time (ticks)
* - SequencerEvent::scheduleReal() scheduled in clock time (seconds)
*
*
* When you need to schedule a lot of events, for instance reproducing
* a Standard MIDI File (SMF) or a MIDI sequence, you may want to use the
* abstract class SequencerOutputThread.
*
* @section Memory
*
* There are two memory issues: the memory pool belongs to the kernel sequencer,
* and can be managed by the class PoolInfo and the methods
* MidiClient::getPoolInfo() and MidiClient::setPoolInfo(). The library buffer
* can be controlled using the methods MidiClient::getOutputBufferSize() and
* MidiClient::setOutputBufferSize() as well as MidiClient::getInputBufferSize()
* and MidiClient::setInputBufferSize().
*
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_client.html
*/
/**
* This class manages event input from the ALSA sequencer.
*/
class MidiClient::SequencerInputThread: public QThread
{
public:
SequencerInputThread(MidiClient *seq, int timeout)
: QThread(),
m_MidiClient(seq),
m_Wait(timeout),
m_Stopped(false),
m_RealTime(true) {}
virtual ~SequencerInputThread() = default;
void run() override;
bool stopped();
void stop();
void setRealtimePriority();
MidiClient *m_MidiClient;
int m_Wait;
bool m_Stopped;
bool m_RealTime;
QReadWriteLock m_mutex;
};
class MidiClient::MidiClientPrivate
{
public:
MidiClientPrivate() :
m_eventsEnabled(false),
m_BlockMode(false),
m_NeedRefreshClientList(true),
m_OpenMode(SND_SEQ_OPEN_DUPLEX),
m_DeviceName("default"),
m_SeqHandle(nullptr),
m_Thread(nullptr),
m_Queue(nullptr),
m_handler(nullptr)
{ }
bool m_eventsEnabled;
bool m_BlockMode;
bool m_NeedRefreshClientList;
int m_OpenMode;
QString m_DeviceName;
snd_seq_t* m_SeqHandle;
QPointer m_Thread;
QPointer m_Queue;
SequencerEventHandler* m_handler;
ClientInfo m_Info;
ClientInfoList m_ClientList;
MidiPortList m_Ports;
PortInfoList m_OutputsAvail;
PortInfoList m_InputsAvail;
QObjectList m_listeners;
SystemInfo m_sysInfo;
PoolInfo m_poolInfo;
};
/**
* Constructor.
*
* This constructor optionally gets a QObject parent. When you create a
* MidiClient with another object as parent, the MidiClient object will
* automatically add itself to the parent's children() list. The parent takes
* ownership of the object i.e. it will automatically delete its children in
* its destructor.
*
* It is necessary to invoke open() later to get the sequencer client handler
* from the ALSA sequencer subsystem.
*
* @param parent The optional parent object
*/
MidiClient::MidiClient( QObject* parent ) :
QObject(parent),
d(new MidiClientPrivate)
{
qRegisterMetaType();
qRegisterMetaType();
}
/**
* Destructor.
*
* The ports and queue associated to this client are automatically released.
*/
MidiClient::~MidiClient()
{
stopSequencerInput();
detachAllPorts();
delete d->m_Queue;
close();
freeClients();
delete d->m_Thread;
}
/**
* Returns the sequencer handler managed by ALSA
* @return the sequencer handler
*/
snd_seq_t*
MidiClient::getHandle()
{
return d->m_SeqHandle;
}
/**
* Returns true if the sequencer is opened
* @return wheter the sequencer is opened
*/
bool MidiClient::isOpened()
{
return !d.isNull() && (d->m_SeqHandle != nullptr);
}
/**
* Returns the name of the sequencer device
* @return the device name
*/
QString MidiClient::getDeviceName()
{
return d->m_DeviceName;
}
/**
* Returns the last open mode used in open()
* @return the last open mode
*/
int MidiClient::getOpenMode()
{
return d->m_OpenMode;
}
/**
* Returns the last block mode used in open()
* @return the last block mode
*/
bool MidiClient::getBlockMode()
{
return d->m_BlockMode;
}
/**
* Returns true if the events mode of delivery has been enabled
* @return whether the events mode of delivery is enabled
*/
bool MidiClient::getEventsEnabled() const
{
return d->m_eventsEnabled;
}
/**
* Sets a sequencer event handler enabling the callback delivery mode
* @param handler the sequencer event handler
*/
void MidiClient::setHandler(SequencerEventHandler* handler)
{
d->m_handler = handler;
}
/**
* Enables real-time priority for the MIDI input thread. The system needs either
* RLIMIT_RTPRIO or RealtimeKit. First RLIMIT_RTPRIO is tried, and if this
* method fails, RealtimeKit is used.
*
* @param enable real-time priority enabled
* @since 0.5.0
*/
void MidiClient::setRealTimeInput(bool enable)
{
if (d->m_Thread == nullptr) {
d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
d->m_Thread->m_RealTime = enable;
}
}
/**
* Return the real-time priority setting for the MIDI input thread.
* @return true if the real-time priority is enabled
* @since 0.5.0
*/
bool MidiClient::realTimeInputEnabled()
{
if (d->m_Thread == nullptr)
return true;
return d->m_Thread->m_RealTime;
}
/**
* Open the sequencer device.
*
* When opening the MidiClient instance, several properties may optionally
* be set as the device name, the open mode and block mode. Default values
* are provided for them. After a successful open, an event with
* SND_SEQ_EVENT_CLIENT_START is broadcast to the announce port.
*
* @param deviceName the sequencer device name, default value = "default".
* This is not a name you make up for your own purposes; it has special
* significance to the ALSA library. Usually you need to pass "default" here.
* @param openMode the open mode, default value = SND_SEQ_OPEN_DUPLEX.
* The read/write mode of the sequencer. Can be one of these three values:
*
* - SND_SEQ_OPEN_OUTPUT - open the sequencer for output only
* - SND_SEQ_OPEN_INPUT - open the sequencer for input only
* - SND_SEQ_OPEN_DUPLEX - open the sequencer for output and input
*
* @param blockMode open in blocking mode, default value = false.
*/
void
MidiClient::open( const QString deviceName,
const int openMode,
const bool blockMode)
{
DRUMSTICK_ALSA_CHECK_ERROR( snd_seq_open( &d->m_SeqHandle, deviceName.toLocal8Bit().data(),
openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) );
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_get_client_info( d->m_SeqHandle, d->m_Info.m_Info ) );
d->m_DeviceName = deviceName;
d->m_OpenMode = openMode;
d->m_BlockMode = blockMode;
}
/**
* Open the sequencer device, providing a configuration object pointer.
*
* This method is like open() except that a configuration is explicitly
* provided. After a successful open, an event with SND_SEQ_EVENT_CLIENT_START
* type is broadcasted from the announce port.
*
* @param conf a configuration object pointer.
* @param deviceName the sequencer device name, default value = "default".
* This is not a name you make up for your own purposes; it has special
* significance to the ALSA library. Usually you need to pass "default" here.
* @param openMode the open mode, default value = SND_SEQ_OPEN_DUPLEX.
* The read/write mode of the sequencer. Can be one of these three values:
*
* - SND_SEQ_OPEN_OUTPUT - open the sequencer for output only
* - SND_SEQ_OPEN_INPUT - open the sequencer for input only
* - SND_SEQ_OPEN_DUPLEX - open the sequencer for output and input
*
* @param blockMode open in blocking mode, default value = false.
*/
void
MidiClient::open( snd_config_t* conf,
const QString deviceName,
const int openMode,
const bool blockMode )
{
DRUMSTICK_ALSA_CHECK_ERROR( snd_seq_open_lconf( &d->m_SeqHandle,
deviceName.toLocal8Bit().data(),
openMode,
blockMode ? 0 : SND_SEQ_NONBLOCK,
conf ));
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info));
d->m_DeviceName = deviceName;
d->m_OpenMode = openMode;
d->m_BlockMode = blockMode;
}
/**
* Close the sequencer device.
*
* After a client is closed, an event with SND_SEQ_EVENT_CLIENT_EXIT is
* broadcast to the announce port. The connection between other clients are
* disconnected. Call this just before exiting your program.
*/
void
MidiClient::close()
{
if (d->m_SeqHandle != nullptr) {
stopSequencerInput();
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_close(d->m_SeqHandle));
d->m_SeqHandle = nullptr;
}
}
/**
* Gets the size of the library output buffer for the ALSA client.
*
* This buffer is used to store the decoded byte-stream of output events before
* transferring to the sequencer.
*
* @return the size of the library output buffer
*/
size_t
MidiClient::getOutputBufferSize()
{
return snd_seq_get_output_buffer_size(d->m_SeqHandle);
}
/**
* Sets the size of the library output buffer for the ALSA client.
*
* This buffer is used to store the decoded byte-stream of output events before
* transferring to the sequencer.
*
* @param newSize the size of the library output buffer
*/
void
MidiClient::setOutputBufferSize(size_t newSize)
{
if (getOutputBufferSize() != newSize) {
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_output_buffer_size(d->m_SeqHandle, newSize));
}
}
/**
* Gets the size of the library input buffer for the ALSA client.
*
* This buffer is used to read a byte-stream of input events before
* transferring from the sequencer.
*
* @return the size of the library input buffer
*/
size_t
MidiClient::getInputBufferSize()
{
return snd_seq_get_input_buffer_size(d->m_SeqHandle);
}
/**
* Sets the size of the library input buffer for the ALSA client.
*
* This buffer is used to read a byte-stream of input events before
* transferring from the sequencer.
*
* @param newSize the size of the library input buffer
*/
void
MidiClient::setInputBufferSize(size_t newSize)
{
if (getInputBufferSize() != newSize) {
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_input_buffer_size(d->m_SeqHandle, newSize));
}
}
/**
* Change the blocking mode of the client.
*
* In block mode, the client falls into sleep when it fills the output memory
* pool with full events. The client will be woken up after a certain amount
* of free space becomes available.
*
* @param newValue the blocking mode
*/
void
MidiClient::setBlockMode(bool newValue)
{
if (d->m_BlockMode != newValue)
{
d->m_BlockMode = newValue;
if (d->m_SeqHandle != nullptr)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_nonblock(d->m_SeqHandle, d->m_BlockMode ? 0 : 1));
}
}
}
/**
* Gets the client ID.
*
* Returns the ID of the client. A client ID is necessary to inquiry or to set
* the client information. A user client ID is assigned from 128 to 191.
*
* @return the client ID.
*/
int
MidiClient::getClientId()
{
return DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_client_id(d->m_SeqHandle));
}
/**
* Returns the type snd_seq_type_t of the given sequencer handle.
* @return the type snd_seq_type_t of the given sequencer handle.
*/
snd_seq_type_t
MidiClient::getSequencerType()
{
return snd_seq_type(d->m_SeqHandle);
}
/**
* Dispatch the events received from the Sequencer.
*
* There are three methods of events delivering:
*
* - A Callback method. To use this method, you must derive a class from
* SequencerEventHandler, overriding the method
* SequencerEventHandler::handleSequencerEvent() to
* provide your own event processing. You must provide the handler instance to
* the client using setHandler().
* - Using QEvent listeners. To use this method, you must use one or more
* classes derived from QObject overriding the method QObject::customEvent().
* You must also use the method addListener() to add such objects to the
* client's listeners list.
* - The third method involves signals and slots. Whenever a sequencer event
* is received, a signal eventReceived() is emitted, that can be connected to
* your own supplied slot(s) to process it.
*
* @see ALSAClient
*/
void
MidiClient::doEvents()
{
do {
int err = 0;
snd_seq_event_t* evp = nullptr;
SequencerEvent* event = nullptr;
err = snd_seq_event_input(d->m_SeqHandle, &evp);
if ((err >= 0) && (evp != nullptr)) {
switch (evp->type) {
case SND_SEQ_EVENT_NOTE:
event = new NoteEvent(evp);
break;
case SND_SEQ_EVENT_NOTEON:
event = new NoteOnEvent(evp);
break;
case SND_SEQ_EVENT_NOTEOFF:
event = new NoteOffEvent(evp);
break;
case SND_SEQ_EVENT_KEYPRESS:
event = new KeyPressEvent(evp);
break;
case SND_SEQ_EVENT_CONTROLLER:
case SND_SEQ_EVENT_CONTROL14:
case SND_SEQ_EVENT_REGPARAM:
case SND_SEQ_EVENT_NONREGPARAM:
event = new ControllerEvent(evp);
break;
case SND_SEQ_EVENT_PGMCHANGE:
event = new ProgramChangeEvent(evp);
break;
case SND_SEQ_EVENT_CHANPRESS:
event = new ChanPressEvent(evp);
break;
case SND_SEQ_EVENT_PITCHBEND:
event = new PitchBendEvent(evp);
break;
case SND_SEQ_EVENT_SYSEX:
event = new SysExEvent(evp);
break;
case SND_SEQ_EVENT_PORT_SUBSCRIBED:
case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
event = new SubscriptionEvent(evp);
break;
case SND_SEQ_EVENT_PORT_CHANGE:
case SND_SEQ_EVENT_PORT_EXIT:
case SND_SEQ_EVENT_PORT_START:
event = new PortEvent(evp);
d->m_NeedRefreshClientList = true;
break;
case SND_SEQ_EVENT_CLIENT_CHANGE:
case SND_SEQ_EVENT_CLIENT_EXIT:
case SND_SEQ_EVENT_CLIENT_START:
event = new ClientEvent(evp);
d->m_NeedRefreshClientList = true;
break;
case SND_SEQ_EVENT_SONGPOS:
case SND_SEQ_EVENT_SONGSEL:
case SND_SEQ_EVENT_QFRAME:
case SND_SEQ_EVENT_TIMESIGN:
case SND_SEQ_EVENT_KEYSIGN:
event = new ValueEvent(evp);
break;
case SND_SEQ_EVENT_SETPOS_TICK:
case SND_SEQ_EVENT_SETPOS_TIME:
case SND_SEQ_EVENT_QUEUE_SKEW:
event = new QueueControlEvent(evp);
break;
case SND_SEQ_EVENT_TEMPO:
event = new TempoEvent(evp);
break;
default:
event = new SequencerEvent(evp);
break;
}
// first, process the callback (if any)
if (d->m_handler != nullptr) {
d->m_handler->handleSequencerEvent(event->clone());
} else {
// second, process the event listeners
if (d->m_eventsEnabled) {
QObjectList::Iterator it;
for(it=d->m_listeners.begin(); it!=d->m_listeners.end(); ++it) {
QObject* sub = (*it);
QCoreApplication::postEvent(sub, event->clone());
}
} else {
// finally, process signals
Q_EMIT eventReceived(event->clone());
}
}
delete event;
}
}
while (snd_seq_event_input_pending(d->m_SeqHandle, 0) > 0);
}
/**
* Starts reading events from the ALSA sequencer.
*/
void
MidiClient::startSequencerInput()
{
if (d->m_Thread == nullptr) {
d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
}
d->m_Thread->start( d->m_Thread->m_RealTime ?
QThread::TimeCriticalPriority : QThread::InheritPriority );
}
/**
* Stops reading events from the ALSA sequencer.
*/
void
MidiClient::stopSequencerInput()
{
int counter = 0;
if (d->m_Thread != nullptr) {
if (d->m_Thread->isRunning()) {
d->m_Thread->stop();
while (!d->m_Thread->wait(500) && (counter < 10)) {
counter++;
}
if (!d->m_Thread->isFinished()) {
d->m_Thread->terminate();
}
}
delete d->m_Thread;
}
}
/**
* Reads the ALSA sequencer's clients list.
*/
void
MidiClient::readClients()
{
ClientInfo cInfo;
freeClients();
cInfo.setClient(-1);
while (snd_seq_query_next_client(d->m_SeqHandle, cInfo.m_Info) >= 0) {
cInfo.readPorts(this);
d->m_ClientList.append(cInfo);
}
d->m_NeedRefreshClientList = false;
}
/**
* Releases the list of ALSA sequencer's clients.
*/
void
MidiClient::freeClients()
{
d->m_ClientList.clear();
}
/**
* Gets the list of clients from the ALSA sequencer.
* @return the list of clients.
*/
ClientInfoList
MidiClient::getAvailableClients()
{
if (d->m_NeedRefreshClientList)
readClients();
ClientInfoList lst = d->m_ClientList; // copy
return lst;
}
/**
* Gets the ClientInfo object holding data about this client.
* @return the ClientInfo object representing this client.
*/
ClientInfo&
MidiClient::getThisClientInfo()
{
snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info);
return d->m_Info;
}
/**
* Sets the data supplied by the ClientInfo object into the ALSA sequencer
* client. This allows to change the name, capabilities, type and other data
* in a single step.
*
* @param val a ClientInfo object reference
*/
void
MidiClient::setThisClientInfo(const ClientInfo& val)
{
d->m_Info = val;
snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
}
/**
* This internal method applies the ClientInfo data to the ALSA sequencer client
*/
void
MidiClient::applyClientInfo()
{
if (d->m_SeqHandle != nullptr) {
snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
}
}
/**
* Gets the client's public name
* @return The client's name
*/
QString
MidiClient::getClientName()
{
return d->m_Info.getName();
}
/**
* Gets the public name corresponding to the given Client ID.
* @param clientId The ID of any existing sequencer client
* @return The client's name
*/
QString
MidiClient::getClientName(const int clientId)
{
ClientInfoList::Iterator it;
if (d->m_NeedRefreshClientList)
readClients();
for (it = d->m_ClientList.begin(); it != d->m_ClientList.end(); ++it) {
if ((*it).getClientId() == clientId) {
return (*it).getName();
}
}
return QString();
}
/**
* Changes the public name of the ALSA sequencer client.
* @param newName A new public name
*/
void
MidiClient::setClientName(QString const& newName)
{
if (newName != d->m_Info.getName()) {
d->m_Info.setName(newName);
applyClientInfo();
}
}
/**
* Gets the list of MidiPort instances belonging to this client.
* @return The list of MidiPort instances.
*/
MidiPortList
MidiClient::getMidiPorts() const
{
return d->m_Ports;
}
/**
* Create and attach a new MidiPort instance to this client.
* @return The pointer to the new MidiPort instance.
*/
MidiPort*
MidiClient::createPort()
{
MidiPort* port = new MidiPort(this);
port->attach(this);
return port;
}
/**
* Attach a MidiPort instance to this client
* @param port The MidiPort to be attached
*/
void
MidiClient::portAttach(MidiPort* port)
{
if (d->m_SeqHandle != nullptr) {
DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_create_port(d->m_SeqHandle, port->m_Info.m_Info));
d->m_Ports.push_back(port);
}
}
/**
* Detach a MidiPort instance from this client
* @param port The MidiPort to be detached
*/
void
MidiClient::portDetach(MidiPort* port)
{
if (d->m_SeqHandle != nullptr) {
if(port->getPortInfo()->getClient() == getClientId())
{
return;
}
DRUMSTICK_ALSA_CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, port->getPortInfo()->getPort()));
port->setMidiClient(nullptr);
MidiPortList::iterator it;
for(it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it)
{
if ((*it)->getPortInfo()->getPort() == port->getPortInfo()->getPort())
{
d->m_Ports.erase(it);
break;
}
}
}
}
/**
* Detach all the ports belonging to this client.
*/
void MidiClient::detachAllPorts()
{
if (d->m_SeqHandle != nullptr) {
QMutableListIterator it(d->m_Ports);
while (it.hasNext()) {
MidiPort* p = it.next();
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_delete_port(d->m_SeqHandle, p->getPortInfo()->getPort()));
p->setMidiClient(nullptr);
it.remove();
}
}
}
/**
* Add an event filter to the client.
* @param evtype An event filter to be added.
*/
void
MidiClient::addEventFilter(int evtype)
{
snd_seq_set_client_event_filter(d->m_SeqHandle, evtype);
}
/**
* Gets the broadcast filter usage of the client.
*
* @return The broadcast filter.
*/
bool
MidiClient::getBroadcastFilter()
{
return d->m_Info.getBroadcastFilter();
}
/**
* Sets the broadcast filter usage of the client.
*
* @param newValue The broadcast filter.
*/
void
MidiClient::setBroadcastFilter(bool newValue)
{
d->m_Info.setBroadcastFilter(newValue);
applyClientInfo();
}
/**
* Get the error-bounce usage of the client.
*
* @return The error-bounce usage.
*/
bool
MidiClient::getErrorBounce()
{
return d->m_Info.getErrorBounce();
}
/**
* Sets the error-bounce usage of the client.
*
* @param newValue The error-bounce usage.
*/
void
MidiClient::setErrorBounce(bool newValue)
{
d->m_Info.setErrorBounce(newValue);
applyClientInfo();
}
/**
* Output an event using the library output buffer.
*
* An event is once expanded on the output buffer. The output buffer will be
* drained automatically if it becomes full.
*
* @param ev The event to be sent.
* @param async Use asynchronous mode. If false, this call will block until the
* event can be delivered.
* @param timeout The maximum time to wait in synchronous mode.
*/
void
MidiClient::output(SequencerEvent* ev, bool async, int timeout)
{
pollfd* pfds = nullptr;
if (async) {
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_event_output(d->m_SeqHandle, ev->getHandle()));
} else {
int npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
pfds = (pollfd*) calloc(npfds, sizeof(pollfd));
snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
while (snd_seq_event_output(d->m_SeqHandle, ev->getHandle()) < 0)
{
poll(pfds, npfds, timeout);
}
free(pfds);
}
}
/**
* Output an event directly to the sequencer
*
* This function sends an event to the sequencer directly not using the library
* output buffer.
*
* @param ev The event to be sent.
* @param async Use asynchronous mode. If false, this call will block until the
* event is delivered to the sequencer.
* @param timeout The maximum time to wait in synchronous mode.
*/
void MidiClient::outputDirect(SequencerEvent* ev, bool async, int timeout)
{
if (async) {
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()));
} else {
int npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
pollfd* pfds = (pollfd*) calloc(npfds, sizeof(pollfd));
snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
while (snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()) < 0)
{
poll(pfds, npfds, timeout);
}
free(pfds);
}
}
/**
* Output an event using the library output buffer, without draining the buffer.
*
* An event is once expanded on the output buffer. The output buffer will NOT be
* drained automatically if it becomes full.
*
* @param ev The event to be sent.
*/
void
MidiClient::outputBuffer(SequencerEvent* ev)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_event_output_buffer(d->m_SeqHandle, ev->getHandle()));
}
/**
* Drain the library output buffer.
*
* This function drains all pending events on the output buffer. The function
* returns immediately after the events are sent to the queues regardless
* whether the events are processed or not.
*
* @param async Use asynchronous mode. If false, this call will block until the
* buffer can be flushed.
* @param timeout The maximum time to wait in synchronous mode.
*/
void MidiClient::drainOutput(bool async, int timeout)
{
if (async) {
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drain_output(d->m_SeqHandle));
} else {
int npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
pollfd* pfds = (pollfd*) calloc(npfds, sizeof(pollfd));
snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
while (snd_seq_drain_output(d->m_SeqHandle) < 0)
{
poll(pfds, npfds, timeout);
}
free(pfds);
}
}
/**
* Wait until all sent events are processed.
*
* This function waits until all events of this client are processed.
*/
void
MidiClient::synchronizeOutput()
{
snd_seq_sync_output_queue(d->m_SeqHandle);
}
/**
* Get the MidiQueue instance associated to this client.
* If the client is not associated to a MidiQueue, one is created.
* @return A MidiQueue instance pointer
*/
MidiQueue*
MidiClient::getQueue()
{
if (d->m_Queue == nullptr) {
createQueue();
}
return d->m_Queue;
}
/**
* Create and return a new MidiQueue associated to this client.
* @return A new MidiQueue instance.
*/
MidiQueue*
MidiClient::createQueue()
{
if (d->m_Queue != nullptr) {
delete d->m_Queue;
}
d->m_Queue = new MidiQueue(this, this);
return d->m_Queue;
}
/**
* Create and return a new MidiQueue with the given name, associated to this
* client.
* @param queueName The name for the new queue.
* @return A new MidiQueue instance.
*/
MidiQueue*
MidiClient::createQueue(QString const& queueName )
{
if (d->m_Queue != nullptr) {
delete d->m_Queue;
}
d->m_Queue = new MidiQueue(this, queueName, this);
return d->m_Queue;
}
/**
* Create a new MidiQueue instance using a queue already existing in the
* system, associating it to the client.
*
* @param queue_id An existing queue identifier.
* @return A new MidiQueue instance.
*/
MidiQueue*
MidiClient::useQueue(int queue_id)
{
if (d->m_Queue != nullptr) {
delete d->m_Queue;
}
d->m_Queue = new MidiQueue(this, queue_id, this);
return d->m_Queue;
}
/**
* Create a new MidiQueue instance using a queue already existing in the
* system, associating it to the client.
*
* @param name An existing queue name.
* @return A new MidiQueue instance.
*/
MidiQueue*
MidiClient::useQueue(const QString& name)
{
if (d->m_Queue != nullptr) {
delete d->m_Queue;
}
int queue_id = getQueueId(name);
if ( queue_id >= 0) {
d->m_Queue = new MidiQueue(this, queue_id, this);
}
return d->m_Queue;
}
/**
* Associate an existing MidiQueue instance to the client.
*
* @param queue An existing MidiQueue.
* @return The provided MidiQueue instance.
*/
MidiQueue*
MidiClient::useQueue(MidiQueue* queue)
{
if (d->m_Queue != nullptr) {
delete d->m_Queue;
}
queue->setParent(this);
d->m_Queue = queue;
return d->m_Queue;
}
/**
* Get a list of the existing queues
* @return a list of existing queues
*/
QList
MidiClient::getAvailableQueues()
{
int q, err, max;
QList queues;
snd_seq_queue_info_t* qinfo;
snd_seq_queue_info_alloca(&qinfo);
max = getSystemInfo().getMaxQueues();
for ( q = 0; q < max; ++q ) {
err = snd_seq_get_queue_info(d->m_SeqHandle, q, qinfo);
if (err == 0) {
queues.append(q);
}
}
return queues;
}
/**
* Gets a list of the available user ports in the system, filtered by the given
* bitmap of desired capabilities.
*
* @param filter A bitmap of capabilities.
* @return A filtered list of the available ports in the system.
*/
PortInfoList
MidiClient::filterPorts(unsigned int filter)
{
PortInfoList result;
ClientInfoList::ConstIterator itc;
PortInfoList::ConstIterator itp;
if (d->m_NeedRefreshClientList)
readClients();
for (itc = d->m_ClientList.constBegin(); itc != d->m_ClientList.constEnd(); ++itc) {
ClientInfo ci = (*itc);
if ((ci.getClientId() == SND_SEQ_CLIENT_SYSTEM) ||
(ci.getClientId() == d->m_Info.getClientId()))
continue;
PortInfoList lstPorts = ci.getPorts();
for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) {
PortInfo pi = (*itp);
unsigned int cap = pi.getCapability();
if ( ((filter & cap) != 0) &&
((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) {
result.append(pi);
}
}
}
return result;
}
/**
* Update the internal lists of user ports.
*/
void
MidiClient::updateAvailablePorts()
{
d->m_InputsAvail.clear();
d->m_OutputsAvail.clear();
d->m_InputsAvail = filterPorts( SND_SEQ_PORT_CAP_READ |
SND_SEQ_PORT_CAP_SUBS_READ );
d->m_OutputsAvail = filterPorts( SND_SEQ_PORT_CAP_WRITE |
SND_SEQ_PORT_CAP_SUBS_WRITE );
}
/**
* Gets the available user input ports in the system.
* @return The list of available input ports.
*/
PortInfoList
MidiClient::getAvailableInputs()
{
d->m_NeedRefreshClientList = true;
updateAvailablePorts();
return d->m_InputsAvail;
}
/**
* Gets the available user output ports in the system.
* @return The list of available output ports.
*/
PortInfoList
MidiClient::getAvailableOutputs()
{
d->m_NeedRefreshClientList = true;
updateAvailablePorts();
return d->m_OutputsAvail;
}
/**
* Adds a QObject to the listeners list. This object should override the method
* QObject::customEvent() to receive SequencerEvent instances.
* @param listener A QObject listener to be notified of received events.
* @see removeListener(), setEventsEnabled()
*/
void
MidiClient::addListener(QObject* listener)
{
d->m_listeners.append(listener);
}
/**
* Removes a QObject listener from the listeners list.
* @param listener listener A QObject listener to be removed of received events.
* @see addListener(), setEventsEnabled()
*/
void
MidiClient::removeListener(QObject* listener)
{
d->m_listeners.removeAll(listener);
}
/**
* Enables the notification of received SequencerEvent instances to the listeners
* registered with addListener()
* @param bEnabled The new state of the events delivering mode.
* @see addListener(), removeListener(), setEventsEnabled()
*/
void
MidiClient::setEventsEnabled(bool bEnabled)
{
if (bEnabled != d->m_eventsEnabled) {
d->m_eventsEnabled = bEnabled;
}
}
/**
* Gets a SystemInfo instance with the updated state of the system.
* @return The updated system info.
*/
SystemInfo&
MidiClient::getSystemInfo()
{
snd_seq_system_info(d->m_SeqHandle, d->m_sysInfo.m_Info);
return d->m_sysInfo;
}
/**
* Gets a PoolInfo instance with an updated state of the client memory pool
* @return The updated memory pool state.
*/
PoolInfo&
MidiClient::getPoolInfo()
{
snd_seq_get_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info);
return d->m_poolInfo;
}
/**
* Applies (updates) the client's PoolInfo data into the system.
* @param info The PoolInfo reference to be applied to the client.
*/
void
MidiClient::setPoolInfo(const PoolInfo& info)
{
d->m_poolInfo = info;
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info));
}
/**
* Resets the client input pool.
* @see dropInput()
*/
void
MidiClient::resetPoolInput()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_reset_pool_input(d->m_SeqHandle));
}
/**
* Resets the client output pool.
* @see dropOutput()
*/
void
MidiClient::resetPoolOutput()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_reset_pool_output(d->m_SeqHandle));
}
/**
* Sets the size of the client's input pool.
* @param size The new size
*/
void
MidiClient::setPoolInput(int size)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_input(d->m_SeqHandle, size));
}
/**
* Sets the size of the client's output pool.
* @param size The new size
*/
void
MidiClient::setPoolOutput(int size)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_output(d->m_SeqHandle, size));
}
/**
* Sets the room size of the client's output pool.
* @param size The new size
*/
void
MidiClient::setPoolOutputRoom(int size)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_pool_output_room(d->m_SeqHandle, size));
}
/**
* Clears the client's input buffer and and remove events in sequencer queue.
* @see resetPoolInput()
*/
void
MidiClient::dropInput()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_input(d->m_SeqHandle));
}
/**
* Remove all events on user-space input buffer.
* @see dropInput()
*/
void
MidiClient::dropInputBuffer()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_input_buffer(d->m_SeqHandle));
}
/**
* Clears the client's output buffer and and remove events in sequencer queue.
*
* This method removes all events on both user-space output buffer and output
* memory pool on kernel.
* @see resetPoolOutput()
*/
void
MidiClient::dropOutput()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_output(d->m_SeqHandle));
}
/**
* Removes all events on the library output buffer.
*
* Removes all events on the user-space output buffer. Unlike dropOutput(), this
* method doesn't remove events on the client's output memory pool.
* @see dropOutput()
*/
void
MidiClient::dropOutputBuffer()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_drop_output_buffer(d->m_SeqHandle));
}
/**
* Removes events on input/output buffers and pools.
* Removes matching events with the given condition from input/output buffers
* and pools. The removal condition is specified in the spec argument.
* @param spec A RemoveEvents instance specifying the removal condition.
*/
void
MidiClient::removeEvents(const RemoveEvents* spec)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_remove_events(d->m_SeqHandle, spec->m_Info));
}
/**
* Extracts (and removes) the first event in the output buffer.
* @return The extracted event.
*/
SequencerEvent*
MidiClient::extractOutput()
{
snd_seq_event_t* ev;
if (DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_extract_output(d->m_SeqHandle, &ev) == 0)) {
return new SequencerEvent(ev);
}
return nullptr;
}
/**
* Returns the size of pending events on the output buffer.
*
* @return The size of pending events.
*/
int
MidiClient::outputPending()
{
return snd_seq_event_output_pending(d->m_SeqHandle);
}
/**
* Gets the size of the events on the input buffer.
*
* If there are events remaining on the user-space input buffer, this method
* returns the total size of events on it. If the argument is true, this method
* checks the presence of events on the sequencer FIFO, and when events exist
* they are transferred to the input buffer, and the number of received events
* are returned. If the argument is false and no events remain on the input
* buffer, this method simply returns zero.
*
* @param fetch Check and fetch the sequencer input pool.
* @return The size in bytes of the remaining input events on the buffer.
*/
int
MidiClient::inputPending(bool fetch)
{
return snd_seq_event_input_pending(d->m_SeqHandle, fetch ? 1 : 0);
}
/**
* Gets the queue's numeric identifier corresponding to the provided name.
*
* @param name The name string to query.
* @return The number of the matching queue.
*/
int
MidiClient::getQueueId(const QString& name)
{
return snd_seq_query_named_queue(d->m_SeqHandle, name.toLocal8Bit().data());
}
/**
* Returns the number of poll descriptors.
* @param events Poll events to be checked (POLLIN and POLLOUT).
* @return The number of poll descriptors.
*/
int
MidiClient::getPollDescriptorsCount(short events)
{
return snd_seq_poll_descriptors_count(d->m_SeqHandle, events);
}
/**
* Get poll descriptors.
*
* Get poll descriptors assigned to the sequencer handle. Since a sequencer
* handle can duplex streams, you need to set which direction(s) is/are polled
* in events argument. When POLLIN bit is specified, the incoming events to the
* ports are checked.
*
* @param pfds Array of poll descriptors
* @param space Space in the poll descriptor array
* @param events Polling events to be checked (POLLIN and POLLOUT)
* @return Count of filled descriptors
*/
int
MidiClient::pollDescriptors( struct pollfd *pfds, unsigned int space,
short events )
{
return snd_seq_poll_descriptors(d->m_SeqHandle, pfds, space, events);
}
/**
* Gets the number of returned events from poll descriptors
* @param pfds Array of poll descriptors.
* @param nfds Count of poll descriptors.
* @return Number of returned events.
*/
unsigned short
MidiClient::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds)
{
unsigned short revents;
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_poll_descriptors_revents( d->m_SeqHandle,
pfds, nfds,
&revents ));
return revents;
}
/**
* Gets the internal sequencer device name
* @return The device name.
*/
const char *
MidiClient::_getDeviceName()
{
return snd_seq_name(d->m_SeqHandle);
}
/**
* Sets the client name
* @param name The new client name.
*/
void
MidiClient::_setClientName(const char *name)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_client_name(d->m_SeqHandle, name));
}
/**
* Create an ALSA sequencer port, without using MidiPort.
* @param name The name of the new port.
* @param caps The new port capabilities.
* @param type The type of the new port.
* @return The port numeric identifier.
*/
int
MidiClient::createSimplePort( const char *name,
unsigned int caps,
unsigned int type )
{
return DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_create_simple_port( d->m_SeqHandle,
name, caps, type ));
}
/**
* Remove an ALSA sequencer port.
* @param port The numeric identifier of the port.
*/
void
MidiClient::deleteSimplePort(int port)
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_delete_simple_port( d->m_SeqHandle, port ));
}
/**
* Subscribe one port from another arbitrary sequencer client:port.
* @param myport The number of the internal port.
* @param client The external client's identifier.
* @param port The external port's identifier.
*/
void
MidiClient::connectFrom(int myport, int client, int port)
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_connect_from(d->m_SeqHandle, myport, client, port ));
}
/**
* Subscribe one port to another arbitrary sequencer client:port.
* @param myport The number of the internal port.
* @param client The external client's identifier.
* @param port The external port's identifier.
*/
void
MidiClient::connectTo(int myport, int client, int port)
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_connect_to(d->m_SeqHandle, myport, client, port ));
}
/**
* Unsubscribe one port from another arbitrary sequencer client:port.
* @param myport The number of the internal port.
* @param client The external client's identifier.
* @param port The external port's identifier.
*/
void
MidiClient::disconnectFrom(int myport, int client, int port)
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_disconnect_from(d->m_SeqHandle, myport, client, port ));
}
/**
* Unsubscribe one port to another arbitrary sequencer client:port.
* @param myport The number of the internal port.
* @param client The external client's identifier.
* @param port The external port's identifier.
*/
void
MidiClient::disconnectTo(int myport, int client, int port)
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_seq_disconnect_to(d->m_SeqHandle, myport, client, port ));
}
/**
* Parse a text address representation, returning an ALSA address record.
*
* This function can be used as a replacement of the standard ALSA function
* snd_seq_parse_address().
*
* @param straddr source text address representation
* @param addr returned ALSA address record
* @return true if the text address was successfully parsed
* @since 0.3.1
*/
bool
MidiClient::parseAddress( const QString& straddr, snd_seq_addr& addr )
{
bool ok(false);
QString testClient, testPort;
ClientInfoList::ConstIterator cit;
int pos = straddr.indexOf(':');
if (pos > -1) {
testClient = straddr.left(pos);
testPort = straddr.mid(pos+1);
} else {
testClient = straddr;
testPort = '0';
}
addr.client = testClient.toInt(&ok);
if (ok)
addr.port = testPort.toInt(&ok);
if (!ok) {
if (d->m_NeedRefreshClientList)
readClients();
for ( cit = d->m_ClientList.constBegin();
cit != d->m_ClientList.constEnd(); ++cit ) {
ClientInfo ci = *cit;
if (testClient.compare(ci.getName(), Qt::CaseInsensitive) == 0) {
addr.client = ci.getClientId();
addr.port = testPort.toInt(&ok);
return ok;
}
}
}
return ok;
}
/**
* Returns true or false depending on the input thread state.
* @return true if the input thread is stopped.
*/
bool
MidiClient::SequencerInputThread::stopped()
{
QReadLocker locker(&m_mutex);
return m_Stopped;
}
/**
* Stops the input thread.
*/
void
MidiClient::SequencerInputThread::stop()
{
QWriteLocker locker(&m_mutex);
m_Stopped = true;
}
#if defined(RTKIT_SUPPORT)
static pid_t _gettid() {
return (pid_t) ::syscall(SYS_gettid);
}
#endif
void
MidiClient::SequencerInputThread::setRealtimePriority()
{
struct sched_param p;
int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK;
quint32 priority = 6;
#if defined(RTKIT_SUPPORT)
bool ok;
quint32 max_prio;
quint64 thread;
struct rlimit old_limit, new_limit;
long long max_rttime;
#endif
::memset(&p, 0, sizeof(p));
p.sched_priority = priority;
rt = ::pthread_setschedparam(::pthread_self(), policy, &p);
if (rt != 0) {
#if defined(RTKIT_SUPPORT)
const QString rtkit_service =
QStringLiteral("org.freedesktop.RealtimeKit1");
const QString rtkit_path =
QStringLiteral("/org/freedesktop/RealtimeKit1");
const QString rtkit_iface = rtkit_service;
thread = _gettid();
QDBusConnection bus = QDBusConnection::systemBus();
QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus);
QVariant maxRTPrio = realtimeKit.property("MaxRealtimePriority");
max_prio = maxRTPrio.toUInt(&ok);
if (!ok) {
qWarning() << "invalid property RealtimeKit.MaxRealtimePriority";
return;
}
if (priority > max_prio)
priority = max_prio;
QVariant maxRTNSec = realtimeKit.property("RTTimeNSecMax");
max_rttime = maxRTNSec.toLongLong(&ok);
if (!ok || max_rttime < 0) {
qWarning() << "invalid property RealtimeKit.RTTimeNSecMax";
return;
}
new_limit.rlim_cur = new_limit.rlim_max = max_rttime;
rt = ::getrlimit(RLIMIT_RTTIME, &old_limit);
if (rt < 0) {
qWarning() << "getrlimit() failed. err=" << rt << ::strerror(rt);
return;
}
rt = ::setrlimit(RLIMIT_RTTIME, &new_limit);
if ( rt < 0) {
qWarning() << "setrlimit() failed, err=" << rt << ::strerror(rt);
return;
}
QDBusMessage reply = realtimeKit.call("MakeThreadRealtime", thread, priority);
if (reply.type() == QDBusMessage::ErrorMessage )
qWarning() << "error returned by RealtimeKit.MakeThreadRealtime:"
<< reply.errorMessage();
#endif
} else {
qWarning() << "pthread_setschedparam() failed, err="
<< rt << ::strerror(rt);
}
}
/**
* Main input thread process loop.
*/
void
MidiClient::SequencerInputThread::run()
{
if ( priority() == TimeCriticalPriority ) {
setRealtimePriority();
}
if (m_MidiClient != nullptr) {
int npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN);
pollfd* pfd = (pollfd *) calloc(npfd, sizeof(pollfd));
try
{
snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN);
while (!stopped() && (m_MidiClient != nullptr))
{
int rt = poll(pfd, npfd, m_Wait);
if (rt > 0) {
m_MidiClient->doEvents();
}
}
}
catch (...)
{
qWarning() << "exception in input thread";
}
free(pfd);
}
}
/**
* Default constructor
*/
ClientInfo::ClientInfo()
{
snd_seq_client_info_malloc(&m_Info);
}
/**
* Copy constructor
* @param other Another ClientInfo reference to be copied
*/
ClientInfo::ClientInfo(const ClientInfo& other)
{
snd_seq_client_info_malloc(&m_Info);
snd_seq_client_info_copy(m_Info, other.m_Info);
m_Ports = other.m_Ports;
}
/**
* Copy constructor
* @param other An existing ALSA client info object
*/
ClientInfo::ClientInfo(snd_seq_client_info_t* other)
{
snd_seq_client_info_malloc(&m_Info);
snd_seq_client_info_copy(m_Info, other);
}
/**
* Constructor
* @param seq A MidiClient object
* @param id A numeric client id
*/
ClientInfo::ClientInfo(MidiClient* seq, int id)
{
snd_seq_client_info_malloc(&m_Info);
snd_seq_get_any_client_info(seq->getHandle(), id, m_Info);
}
/**
* Destructor
*/
ClientInfo::~ClientInfo()
{
freePorts();
snd_seq_client_info_free(m_Info);
}
/**
* Clone the client info object.
* @return A pointer to the new object.
*/
ClientInfo*
ClientInfo::clone()
{
return new ClientInfo(m_Info);
}
/**
* Assignment operator
* @param other Another ClientInfo object
* @return This object
*/
ClientInfo&
ClientInfo::operator=(const ClientInfo& other)
{
if (this == &other)
return *this;
snd_seq_client_info_copy(m_Info, other.m_Info);
m_Ports = other.m_Ports;
return *this;
}
/**
* Gets the client's numeric identifier.
* @return The client's numeric identifier.
*/
int
ClientInfo::getClientId()
{
return snd_seq_client_info_get_client(m_Info);
}
/**
* Gets the client's type
* @return The client's type.
*/
snd_seq_client_type_t
ClientInfo::getClientType()
{
return snd_seq_client_info_get_type(m_Info);
}
/**
* Gets the client's name
* @return The client's name.
*/
QString
ClientInfo::getName()
{
return QString(snd_seq_client_info_get_name(m_Info));
}
/**
* Gets the client's broadcast filter
* @return The client's broadcast filter.
*/
bool
ClientInfo::getBroadcastFilter()
{
return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0);
}
/**
* Gets the client's error bounce
* @return The client's error bounce.
*/
bool
ClientInfo::getErrorBounce()
{
return (snd_seq_client_info_get_error_bounce(m_Info) != 0);
}
/**
* Gets the client's event filter.
* @return The client's event filter.
* @deprecated Use isFiltered() instead.
*/
const unsigned char*
ClientInfo::getEventFilter()
{
return snd_seq_client_info_get_event_filter(m_Info);
}
/**
* Gets the client's port count.
* @return The client's port count.
*/
int
ClientInfo::getNumPorts()
{
return snd_seq_client_info_get_num_ports(m_Info);
}
/**
* Gets the number of lost events.
* @return The number of lost events.
*/
int
ClientInfo::getEventLost()
{
return snd_seq_client_info_get_event_lost(m_Info);
}
/**
* Sets the client identifier number.
* @param client The client identifier number.
*/
void
ClientInfo::setClient(int client)
{
snd_seq_client_info_set_client(m_Info, client);
}
/**
* Sets the client name.
* @param name The client name.
*/
void
ClientInfo::setName(QString name)
{
snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data());
}
/**
* Sets the broadcast filter.
* @param val The broadcast filter.
*/
void
ClientInfo::setBroadcastFilter(bool val)
{
snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0);
}
/**
* Sets the error bounce.
* @param val The error bounce.
*/
void
ClientInfo::setErrorBounce(bool val)
{
snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0);
}
/**
* Sets the event filter.
* @param filter The event filter.
* @deprecated Use addFilter() instead.
*/
void
ClientInfo::setEventFilter(unsigned char *filter)
{
snd_seq_client_info_set_event_filter(m_Info, filter);
}
/**
* Read the client ports.
* @param seq The client instance.
*/
void
ClientInfo::readPorts(MidiClient* seq)
{
PortInfo info;
freePorts();
info.setClient(getClientId());
info.setClientName(getName());
info.setPort(-1);
while (snd_seq_query_next_port(seq->getHandle(), info.m_Info) >= 0) {
info.readSubscribers(seq);
m_Ports.append(info);
}
}
/**
* Release the ports list.
*/
void
ClientInfo::freePorts()
{
m_Ports.clear();
}
/**
* Gets the ports list.
* @return The ports list.
*/
PortInfoList
ClientInfo::getPorts() const
{
PortInfoList lst = m_Ports; // copy
return lst;
}
/**
* Gets the size of the internal object.
* @return The size of the internal object.
*/
int
ClientInfo::getSizeOfInfo() const
{
return snd_seq_client_info_sizeof();
}
#if SND_LIB_VERSION > 0x010010
/**
* Adds an event type to the client's filter.
*
* @param eventType The new event's type.
*/
void
ClientInfo::addFilter(int eventType)
{
snd_seq_client_info_event_filter_add(m_Info, eventType);
}
/**
* Checks id the given event's type is filtered.
* @param eventType The event's type.
* @return true if the event type is filtered
*/
bool
ClientInfo::isFiltered(int eventType)
{
return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0);
}
/**
* Clear the client's event filter
*/
void
ClientInfo::clearFilter()
{
snd_seq_client_info_event_filter_clear(m_Info);
}
/**
* Removes the event type from the client's filter.
* @param eventType The event's type.
*/
void
ClientInfo::removeFilter(int eventType)
{
snd_seq_client_info_event_filter_del(m_Info, eventType);
}
#endif
/**
* Default constructor
*/
SystemInfo::SystemInfo()
{
snd_seq_system_info_malloc(&m_Info);
}
/**
* Copy constructor
* @param other Another SystemInfo object reference to be copied
*/
SystemInfo::SystemInfo(const SystemInfo& other)
{
snd_seq_system_info_malloc(&m_Info);
snd_seq_system_info_copy(m_Info, other.m_Info);
}
/**
* Copy constructor
* @param other Another ALSA system info object to be copied
*/
SystemInfo::SystemInfo(snd_seq_system_info_t* other)
{
snd_seq_system_info_malloc(&m_Info);
snd_seq_system_info_copy(m_Info, other);
}
/**
* Constructor
* @param seq A MidiClient object
*/
SystemInfo::SystemInfo(MidiClient* seq)
{
snd_seq_system_info_malloc(&m_Info);
snd_seq_system_info(seq->getHandle(), m_Info);
}
/**
* Destructor
*/
SystemInfo::~SystemInfo()
{
snd_seq_system_info_free(m_Info);
}
/**
* Clone the system info object
* @return A pointer to the new object
*/
SystemInfo*
SystemInfo::clone()
{
return new SystemInfo(m_Info);
}
/**
* Assignment operator
* @param other Another SystemInfo object
* @return This object
*/
SystemInfo&
SystemInfo::operator=(const SystemInfo& other)
{
if (this == &other)
return *this;
snd_seq_system_info_copy(m_Info, other.m_Info);
return *this;
}
/**
* Get the system's maximum number of clients.
* @return The maximum number of clients.
*/
int SystemInfo::getMaxClients()
{
return snd_seq_system_info_get_clients(m_Info);
}
/**
* Get the system's maximum number of ports.
* @return The maximum number of ports.
*/
int SystemInfo::getMaxPorts()
{
return snd_seq_system_info_get_ports(m_Info);
}
/**
* Get the system's maximum number of queues.
* @return The system's maximum number of queues.
*/
int SystemInfo::getMaxQueues()
{
return snd_seq_system_info_get_queues(m_Info);
}
/**
* Get the system's maximum number of channels.
* @return The system's maximum number of channels.
*/
int SystemInfo::getMaxChannels()
{
return snd_seq_system_info_get_channels(m_Info);
}
/**
* Get the system's current number of queues.
* @return The system's current number of queues.
*/
int SystemInfo::getCurrentQueues()
{
return snd_seq_system_info_get_cur_queues(m_Info);
}
/**
* Get the system's current number of clients.
* @return The system's current number of clients.
*/
int SystemInfo::getCurrentClients()
{
return snd_seq_system_info_get_cur_clients(m_Info);
}
/**
* Get the system's info object size.
* @return The system's info object size.
*/
int SystemInfo::getSizeOfInfo() const
{
return snd_seq_system_info_sizeof();
}
/**
* Default constructor
*/
PoolInfo::PoolInfo()
{
snd_seq_client_pool_malloc(&m_Info);
}
/**
* Copy constructor
* @param other Another PoolInfo object reference to be copied
*/
PoolInfo::PoolInfo(const PoolInfo& other)
{
snd_seq_client_pool_malloc(&m_Info);
snd_seq_client_pool_copy(m_Info, other.m_Info);
}
/**
* Copy constructor
* @param other An ALSA pool info object to be copied
*/
PoolInfo::PoolInfo(snd_seq_client_pool_t* other)
{
snd_seq_client_pool_malloc(&m_Info);
snd_seq_client_pool_copy(m_Info, other);
}
/**
* Constructor
* @param seq A MidiClient object
*/
PoolInfo::PoolInfo(MidiClient* seq)
{
snd_seq_client_pool_malloc(&m_Info);
snd_seq_get_client_pool(seq->getHandle(), m_Info);
}
/**
* Destructor
*/
PoolInfo::~PoolInfo()
{
snd_seq_client_pool_free(m_Info);
}
/**
* Clone the pool info obeject
* @return A pointer to the new object
*/
PoolInfo*
PoolInfo::clone()
{
return new PoolInfo(m_Info);
}
/**
* Assignment operator
* @param other Another PoolInfo object reference to be copied
* @return This object
*/
PoolInfo&
PoolInfo::operator=(const PoolInfo& other)
{
if (this == &other)
return *this;
snd_seq_client_pool_copy(m_Info, other.m_Info);
return *this;
}
/**
* Gets the client ID for this object.
* @return The client ID.
*/
int
PoolInfo::getClientId()
{
return snd_seq_client_pool_get_client(m_Info);
}
/**
* Gets the available size on input pool.
* @return The available size on input pool.
*/
int
PoolInfo::getInputFree()
{
return snd_seq_client_pool_get_input_free(m_Info);
}
/**
* Gets the input pool size.
* @return The input pool size.
*/
int
PoolInfo::getInputPool()
{
return snd_seq_client_pool_get_input_pool(m_Info);
}
/**
* Gets the available size on output pool.
* @return The available size on output pool.
*/
int
PoolInfo::getOutputFree()
{
return snd_seq_client_pool_get_output_free(m_Info);
}
/**
* Gets the output pool size.
* @return The output pool size.
*/
int
PoolInfo::getOutputPool()
{
return snd_seq_client_pool_get_output_pool(m_Info);
}
/**
* Gets the output room size.
* The output room is the minimum pool size for select/blocking mode.
* @return The output room size.
*/
int
PoolInfo::getOutputRoom()
{
return snd_seq_client_pool_get_output_room(m_Info);
}
/**
* Set the input pool size.
* @param size The input pool size.
*/
void
PoolInfo::setInputPool(int size)
{
snd_seq_client_pool_set_input_pool(m_Info, size);
}
/**
* Sets the output pool size.
* @param size The output pool size.
*/
void
PoolInfo::setOutputPool(int size)
{
snd_seq_client_pool_set_output_pool(m_Info, size);
}
/**
* Sets the output room size.
* The output room is the minimum pool size for select/blocking mode.
*
* @param size Output room size
*/
void
PoolInfo::setOutputRoom(int size)
{
snd_seq_client_pool_set_output_room(m_Info, size);
}
/**
* Gets the size of the client pool object.
* @return The size of the client pool object.
*/
int
PoolInfo::getSizeOfInfo() const
{
return snd_seq_client_pool_sizeof();
}
#if SND_LIB_VERSION > 0x010004
/**
* Gets the runtime ALSA library version string
* @return string representing the runtime ALSA library version
* @since 0.3.0
*/
QString
getRuntimeALSALibraryVersion()
{
return QString(snd_asoundlib_version());
}
/**
* Gets the runtime ALSA library version number
* @return integer representing the runtime ALSA library version
* @since 0.3.0
*/
int
getRuntimeALSALibraryNumber()
{
QRegularExpression rx("(\\d+)");
QString str = getRuntimeALSALibraryVersion();
bool ok;
int result = 0, j = 0;
QRegularExpressionMatchIterator i = rx.globalMatch(str);
while (i.hasNext() && (j < 3)) {
QRegularExpressionMatch m = i.next();
int v = m.captured(1).toInt(&ok);
if (ok) {
result <<= 8;
result += v;
}
j++;
}
return result;
}
#endif // SND_LIB_VERSION > 0x010004
/**
* Gets the runtime ALSA drivers version string
* @return string representing the runtime ALSA drivers version
* @since 0.3.0
*/
QString
getRuntimeALSADriverVersion()
{
QRegularExpression rx("([\\d\\.]+)");
QString s;
QFile f("/proc/asound/version");
if (f.open(QFile::ReadOnly)) {
QTextStream str(&f);
QString sub = str.readLine().trimmed();
QRegularExpressionMatch m = rx.match(sub);
if (m.hasMatch()) {
s = m.captured(1);
}
}
return s;
}
/**
* Gets the runtime ALSA drivers version number
* @return integer representing the runtime ALSA drivers version
* @since 0.3.0
*/
int
getRuntimeALSADriverNumber()
{
QRegularExpression rx("(\\d+)");
QString str = getRuntimeALSADriverVersion();
bool ok;
int result = 0, j = 0;
QRegularExpressionMatchIterator i = rx.globalMatch(str);
while (i.hasNext() && (j < 3)) {
QRegularExpressionMatch m = i.next();
int v = m.captured(1).toInt(&ok);
if (ok) {
result <<= 8;
result += v;
}
j++;
}
return result;
}
/**
* ALSA library version at build time.
*
* This string corresponds to the compilation library, which may be
* different to the runtime library.
* @return ALSA runtime library formatted as a QString
* @see getRuntimeALSALibraryVersion
*/
QString getCompiledALSALibraryVersion()
{
return QStringLiteral(SND_LIB_VERSION_STR);
}
/**
* @brief getDrumstickLibraryVersion provides the Drumstick version as an edited QString
* @return Drumstick library version
*/
QString getDrumstickLibraryVersion()
{
return QStringLiteral(QT_STRINGIFY(VERSION));
}
/** @} */
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/alsa/alsaport.cpp 0000644 0001750 0001750 00000064334 14541630232 017462 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include "errorcheck.h"
#include
#include
/**
* @file alsaport.cpp
* Implementation of classes managing ALSA Sequencer ports.
*/
namespace drumstick {
namespace ALSA {
/**
* @addtogroup ALSAPort
* @{
*
* Ports are the endpoints of the MIDI connections.
*
* Ports can be readable, writable, or both. They can be private for the owner
* application, or can be subscribed by a third application.
*
* The ALSA sequencer readable ports are equivalent to the MIDI OUT ports in the
* real world. Similarly, the writable ports are equivalent to the MIDI IN ones.
*
* Classes:
*
* PortInfo is a container to retrieve and change some properties about the ALSA
* MIDI ports.
*
* MidiPort represents an ALSA MIDI port.
*
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_port.html
* @}
*/
/**
* Default constructor.
*/
PortInfo::PortInfo()
{
snd_seq_port_info_malloc(&m_Info);
}
/**
* Copy constructor
* @param other Another PortInfo object reference
*/
PortInfo::PortInfo(const PortInfo& other)
{
snd_seq_port_info_malloc(&m_Info);
snd_seq_port_info_copy(m_Info, other.m_Info);
m_ReadSubscribers = other.m_ReadSubscribers;
m_WriteSubscribers = other.m_WriteSubscribers;
m_ClientName = other.m_ClientName;
}
/**
* Constructor
* @param other An ALSA port info object pointer
*/
PortInfo::PortInfo(snd_seq_port_info_t* other)
{
snd_seq_port_info_malloc(&m_Info);
snd_seq_port_info_copy(m_Info, other);
}
/**
* Constructor
* @param seq A MidiClient instance
* @param client An existing client number
* @param port An existing port number
*/
PortInfo::PortInfo(MidiClient* seq, const int client, const int port)
{
snd_seq_port_info_malloc(&m_Info);
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_any_port_info(seq->getHandle(), client, port, m_Info));
}
/**
* Constructor
* @param seq A MidiClient instance
* @param port An existing port number
*/
PortInfo::PortInfo(MidiClient* seq, const int port)
{
snd_seq_port_info_malloc(&m_Info);
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_get_port_info(seq->getHandle(), port, m_Info));
}
/**
* Destructor
*/
PortInfo::~PortInfo()
{
snd_seq_port_info_free(m_Info);
freeSubscribers();
}
/**
* Copy the current object
* @return A pointer to the new object
*/
PortInfo* PortInfo::clone()
{
return new PortInfo(m_Info);
}
/**
* Assignment operator
* @param other Another PortInfo object reference
* @return This object
*/
PortInfo& PortInfo::operator=(const PortInfo& other)
{
if (this == &other)
return *this;
snd_seq_port_info_copy(m_Info, other.m_Info);
m_ReadSubscribers = other.m_ReadSubscribers;
m_WriteSubscribers = other.m_WriteSubscribers;
m_ClientName = other.m_ClientName;
return *this;
}
/**
* Gets the client number
* @return The client number
* @see setClient()
*/
int
PortInfo::getClient()
{
return snd_seq_port_info_get_client(m_Info);
}
/**
* Gets the port number
* @return The port number
* @see setPort()
*/
int
PortInfo::getPort()
{
return snd_seq_port_info_get_port(m_Info);
}
/**
* Gets the client name.
* @return the client name
* @see setClientName()
*/
QString PortInfo::getClientName() const
{
return m_ClientName;
}
/**
* Gets the address record for this port
* @return A pointer to the address record
* @see setAddr()
*/
const snd_seq_addr_t*
PortInfo::getAddr()
{
return snd_seq_port_info_get_addr(m_Info);
}
/**
* Gets the port name
* @return The port name
* @see setName()
*/
QString
PortInfo::getName()
{
return QString(snd_seq_port_info_get_name(m_Info));
}
/**
* Gets the capabilities bitmap
* @return The capabilities bitmap
* @see setCapability()
*/
unsigned int
PortInfo::getCapability()
{
return snd_seq_port_info_get_capability(m_Info);
}
/**
* Gets the port type
* @return The port type
* @see setType()
*/
unsigned int
PortInfo::getType()
{
return snd_seq_port_info_get_type(m_Info);
}
/**
* Gets the MIDI channels
* @return The MIDI channels
* @see setMidiChannels()
*/
int
PortInfo::getMidiChannels()
{
return snd_seq_port_info_get_midi_channels(m_Info);
}
/**
* Gets the MIDI voices
* @return The MIDI voices
* @see setMidiVoices()
*/
int
PortInfo::getMidiVoices()
{
return snd_seq_port_info_get_midi_voices(m_Info);
}
/**
* Gets the synth voices
* @return The synth voices
* @see setSynthVoices()
*/
int
PortInfo::getSynthVoices()
{
return snd_seq_port_info_get_synth_voices(m_Info);
}
/**
* Get the number of read subscriptions.
* @return The number of read subscriptions.
*/
int
PortInfo::getReadUse()
{
return snd_seq_port_info_get_read_use(m_Info);
}
/**
* Gets the number of write subscriptions.
* @return The number of write subscriptions.
*/
int
PortInfo::getWriteUse()
{
return snd_seq_port_info_get_write_use(m_Info);
}
/**
* Gets the port-specified mode.
* @return The port-specified mode.
* @see setPortSpecified()
*/
int
PortInfo::getPortSpecified()
{
return snd_seq_port_info_get_port_specified(m_Info);
}
/**
* Sets the client number
* @param client The client number
* @see getClient()
*/
void
PortInfo::setClient(int client)
{
snd_seq_port_info_set_client(m_Info, client);
}
/**
* Set the port number
* @param port The port number
* @see getPort()
*/
void
PortInfo::setPort(int port)
{
snd_seq_port_info_set_port(m_Info, port);
}
/**
* Sets the address record
* @param addr An address record pointer
* @see getAddr()
*/
void
PortInfo::setAddr(const snd_seq_addr_t* addr)
{
snd_seq_port_info_set_addr(m_Info, addr);
}
/**
* Sets the port name
* @param name The port name
* @see getName()
*/
void
PortInfo::setName(QString const& name)
{
snd_seq_port_info_set_name(m_Info, name.toLocal8Bit().data());
}
/**
* Sets the capability bitmap.
*
* Each port has the capability bitmaps to specify the access of
* the port from other clients. The capability bit flags are:
*
* - SND_SEQ_PORT_CAP_READ Readable from this port
* - SND_SEQ_PORT_CAP_WRITE Writable to this port
* - SND_SEQ_PORT_CAP_DUPLEX Read/write duplex access is supported
* - SND_SEQ_PORT_CAP_SUBS_READ Read subscription is allowed
* - SND_SEQ_PORT_CAP_SUBS_WRITE Write subscription is allowed
* - SND_SEQ_PORT_CAP_NO_EXPORT Subscription management from 3rd clients is disallowed
*
* @param capability The capability bitmap.
* @see getCapability()
*/
void
PortInfo::setCapability(unsigned int capability)
{
snd_seq_port_info_set_capability(m_Info, capability);
}
/**
* Sets the port type.
*
* The port type is defined combining some of the type bit flags:
*
* - SND_SEQ_PORT_TYPE_SPECIFIC Hardware specific port
* - SND_SEQ_PORT_TYPE_MIDI_GENERIC Generic MIDI device
* - SND_SEQ_PORT_TYPE_MIDI_GM General MIDI compatible device
* - SND_SEQ_PORT_TYPE_MIDI_GM2 General MIDI 2 compatible device
* - SND_SEQ_PORT_TYPE_MIDI_GS GS compatible device
* - SND_SEQ_PORT_TYPE_MIDI_XG XG compatible device
* - SND_SEQ_PORT_TYPE_MIDI_MT32 MT-32 compatible device
* - SND_SEQ_PORT_TYPE_HARDWARE Implemented in hardware
* - SND_SEQ_PORT_TYPE_SOFTWARE Implemented in software
* - SND_SEQ_PORT_TYPE_SYNTHESIZER Generates sound
* - SND_SEQ_PORT_TYPE_PORT Connects to other device(s)
* - SND_SEQ_PORT_TYPE_APPLICATION Application (sequencer/editor)
*
* @param type The port type bitmap
* @see getType()
*/
void
PortInfo::setType(unsigned int type)
{
snd_seq_port_info_set_type(m_Info, type);
}
/**
* Set the MIDI channels
* @param channels The MIDI channels
* @see getMidiChannels()
*/
void
PortInfo::setMidiChannels(int channels)
{
snd_seq_port_info_set_midi_channels(m_Info, channels);
}
/**
* Sets the MIDI voices
* @param voices The MIDI voices
* @see getMidiVoices()
*/
void
PortInfo::setMidiVoices(int voices)
{
snd_seq_port_info_set_midi_voices(m_Info, voices);
}
/**
* Sets the synth voices
* @param voices The synth voices
* @see getSynthVoices()
*/
void
PortInfo::setSynthVoices(int voices)
{
snd_seq_port_info_set_synth_voices(m_Info, voices);
}
/**
* Sets the port-specified mode
* @param val The port-specified mode.
* @see getPortSpecified()
*/
void
PortInfo::setPortSpecified(int val)
{
snd_seq_port_info_set_port_specified(m_Info, val);
}
/**
* Gets the list of read subscribers
* @return The list of read subscribers
*/
SubscribersList
PortInfo::getReadSubscribers() const
{
return m_ReadSubscribers; // copy
}
/**
* Gets the list of write subscribers
* @return The list of write subscribers
*/
SubscribersList
PortInfo::getWriteSubscribers() const
{
return m_WriteSubscribers; // copy
}
/**
* Obtains the port subscribers lists
* @param seq An opened MidiClient instance
*/
void
PortInfo::readSubscribers(MidiClient* seq)
{
Subscriber subs;
snd_seq_addr_t tmp;
freeSubscribers();
tmp.client = getClient();
tmp.port = getPort();
// Read subs
subs.setType(SND_SEQ_QUERY_SUBS_READ);
subs.setIndex(0);
subs.setRoot(&tmp);
while (snd_seq_query_port_subscribers(seq->getHandle(), subs.m_Info) >= 0)
{
m_ReadSubscribers.append(subs);
subs.setIndex(subs.getIndex() + 1);
}
// Write subs
subs.setType(SND_SEQ_QUERY_SUBS_WRITE);
subs.setIndex(0);
subs.setRoot(&tmp);
while (snd_seq_query_port_subscribers(seq->getHandle(), subs.m_Info) >= 0)
{
m_WriteSubscribers.append(subs);
subs.setIndex(subs.getIndex() + 1);
}
}
/**
* Releases the subscribers lists
*/
void
PortInfo::freeSubscribers()
{
m_ReadSubscribers.clear();
m_WriteSubscribers.clear();
}
/**
* Sets the client name.
* @see getClientName()
* @param name Client name
*/
void PortInfo::setClientName(QString name)
{
m_ClientName = name;
}
/**
* Gets the size of the ALSA info object
* @return The size of the object
*/
int
PortInfo::getSizeOfInfo() const
{
return snd_seq_port_info_sizeof();
}
/**
* Gets the timestamping mode
* @return The timestamping mode
* @see setTimestamping()
*/
bool
PortInfo::getTimestamping()
{
return (snd_seq_port_info_get_timestamping(m_Info) == 1);
}
/**
* Gets the timestamping real mode
* @return The timestamping real mode
* @see setTimestampReal()
*/
bool
PortInfo::getTimestampReal()
{
return (snd_seq_port_info_get_timestamp_real(m_Info) == 1);
}
/**
* Gets the timestamping queue number
* @return The timestamping queue number
* @see setTimestampQueue()
*/
int
PortInfo::getTimestampQueue()
{
return snd_seq_port_info_get_timestamp_queue(m_Info);
}
/**
* Sets the timestamping mode
* @param value The timestamping mode
* @see getTimestamping()
*/
void
PortInfo::setTimestamping(bool value)
{
snd_seq_port_info_set_timestamping(m_Info, value?1:0);
}
/**
* Sets the timestamping real mode
* @param value The timestamping real mode
* @see getTimestampReal()
*/
void
PortInfo::setTimestampReal(bool value)
{
snd_seq_port_info_set_timestamp_real(m_Info, value?1:0);
}
/**
* Sets the timestamp queue number
* @param queueId The timestamp queue number
* @see getTimestampQueue()
*/
void
PortInfo::setTimestampQueue(int queueId)
{
snd_seq_port_info_set_timestamp_queue(m_Info, queueId);
}
/**
* Constructor
* @param parent An optional parent object
*/
MidiPort::MidiPort( QObject* parent ) :
QObject( parent ),
m_MidiClient( nullptr ),
m_Attached( false )
{}
/**
* Destructor.
*
* All subscriptions are released.
*/
MidiPort::~MidiPort()
{
unsubscribeAll();
detach();
freeSubscriptions();
}
/**
* Gets the PortInfo object pointer
* @return the PortInfo object pointer
*/
PortInfo*
MidiPort::getPortInfo()
{
return &m_Info;
}
/**
* Gets the list of susbcriptions
* @return The list of susbcriptions
*/
SubscriptionsList
MidiPort::getSubscriptions() const
{
return m_Subscriptions;
}
/**
* Releases the lists of subscriptions.
*/
void
MidiPort::freeSubscriptions()
{
m_Subscriptions.clear();
}
/**
* Sets the MidiClient
* @param seq A MidiClient object pointer
*/
void
MidiPort::setMidiClient( MidiClient* seq )
{
if (m_MidiClient != seq)
{
m_MidiClient = seq;
Q_EMIT midiClientChanged( this, m_MidiClient );
applyPortInfo();
}
}
/**
* Subscribe a Subscription object
* @param subs A Subscription object pointer
*/
void
MidiPort::subscribe(Subscription* subs)
{
subs->subscribe(m_MidiClient);
m_Subscriptions.append(*subs);
Q_EMIT subscribed(this, subs);
}
/**
* Unsubscribe a Subscription object
* @param subs A Subscription object pointer
*/
void
MidiPort::unsubscribe( Subscription* subs )
{
Subscription subs2;
if (m_MidiClient == nullptr)
{
return;
}
subs->unsubscribe(m_MidiClient);
SubscriptionsList::iterator it;
for(it = m_Subscriptions.begin(); it != m_Subscriptions.end(); ++it)
{
subs2 = (*it);
if ((subs2.getSender()->client == subs->getSender()->client) &&
(subs2.getSender()->port == subs->getSender()->port) &&
(subs2.getDest()->client == subs->getDest()->client) &&
(subs2.getDest()->port == subs->getDest()->port))
{
m_Subscriptions.erase(it);
break;
}
}
}
/**
* Subscribe to another port destination
* @param info A PortInfo object pointer
*/
void
MidiPort::subscribeTo( PortInfo* info )
{
Subscription subs;
subs.setSender(m_Info.getAddr());
subs.setDest(info->getAddr());
subscribe(&subs);
}
/**
* Susbcribe to another port destination
* @param client ALSA client number
* @param port ALSA port number
*/
void
MidiPort::subscribeTo( int client, int port )
{
Subscription subs;
snd_seq_addr addr;
addr.client = client;
addr.port = port;
subs.setSender(m_Info.getAddr());
subs.setDest(&addr);
subscribe(&subs);
}
/**
* Subscribe to another port destination
* @param name A string representing a client:port pair
*/
void
MidiPort::subscribeTo( QString const& name )
{
Subscription subs;
snd_seq_addr addr;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
subs.setSender(m_Info.getAddr());
if (m_MidiClient->parseAddress(name, addr)) {
subs.setDest(&addr);
subscribe(&subs);
}
}
}
/**
* Unsubscribe a destination port
* @param name A string representing a client:port pair
*/
void
MidiPort::unsubscribeTo( QString const& name )
{
Subscription subs;
snd_seq_addr addr;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
subs.setSender(m_Info.getAddr());
if (m_MidiClient->parseAddress(name, addr)) {
subs.setDest(&addr);
unsubscribe(&subs);
}
}
}
/**
* Unsubscribe a destination port
* @param port A PortInfo object pointer
*/
void
MidiPort::unsubscribeTo( PortInfo* port )
{
Subscription subs;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
subs.setSender(m_Info.getAddr());
subs.setDest(port->getAddr());
unsubscribe(&subs);
}
}
/**
* Unsubscribe a destination port
* @param addr An ALSA address record pointer
*/
void
MidiPort::unsubscribeTo( const snd_seq_addr_t* addr )
{
Subscription subs;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
subs.setSender(m_Info.getAddr());
subs.setDest(addr);
unsubscribe(&subs);
}
}
/**
* Subscribe a source port
* @param port A PortInfo object pointer
*/
void
MidiPort::subscribeFrom( PortInfo* port )
{
Subscription subs;
subs.setSender( port->getAddr() );
subs.setDest( m_Info.getAddr() );
subscribe(&subs);
}
/**
* Subscribe a source port
* @param client ALSA client number
* @param port ALSA port number
*/
void
MidiPort::subscribeFrom( int client, int port )
{
Subscription subs;
snd_seq_addr addr;
addr.client = client;
addr.port = port;
subs.setSender(&addr);
subs.setDest(m_Info.getAddr());
subscribe(&subs);
}
/**
* Subscribe a source port
* @param name A string representing a client:port pair
*/
void
MidiPort::subscribeFrom( QString const& name )
{
Subscription subs;
snd_seq_addr addr;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
if (m_MidiClient->parseAddress(name, addr)) {
subs.setSender(&addr);
subs.setDest(m_Info.getAddr());
subscribe(&subs);
}
}
}
/**
* Unsubscribe a source port
* @param name A string representing a client:port pair
*/
void
MidiPort::unsubscribeFrom( QString const& name )
{
Subscription subs;
snd_seq_addr addr;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
if (m_MidiClient->parseAddress(name, addr)) {
subs.setSender(&addr);
subs.setDest(m_Info.getAddr());
unsubscribe(&subs);
}
}
}
/**
* Unsubscribe a source port
* @param port A PortInfo object pointer
*/
void
MidiPort::unsubscribeFrom( PortInfo* port )
{
Subscription subs;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
subs.setSender(port->getAddr());
subs.setDest(m_Info.getAddr());
unsubscribe(&subs);
}
}
/**
* Unsubscribe a source port
* @param addr An ALSA address record pointer
*/
void
MidiPort::unsubscribeFrom( const snd_seq_addr_t* addr )
{
Subscription subs;
if ((m_MidiClient != nullptr) && (m_MidiClient->getHandle() != nullptr))
{
subs.setSender(addr);
subs.setDest(m_Info.getAddr());
unsubscribe(&subs);
}
}
/**
* Subscribe from the System:announce port
*/
void
MidiPort::subscribeFromAnnounce()
{
subscribeFrom(SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
}
/**
* Unsubscribe all subscriptions
*/
void
MidiPort::unsubscribeAll()
{
if (m_MidiClient == nullptr) {
return;
}
SubscriptionsList::Iterator it;
for( it = m_Subscriptions.begin(); it != m_Subscriptions.end(); ++it) {
Subscription s = (*it);
s.unsubscribe(m_MidiClient);
}
m_Subscriptions.clear();
}
/**
* Applies all the the delayed PortInfo changes to the MIDI port object
*/
void
MidiPort::applyPortInfo()
{
if (m_Attached && (m_MidiClient != nullptr) && (m_MidiClient->isOpened()))
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_seq_set_port_info( m_MidiClient->getHandle(),
m_Info.getPort(), m_Info.m_Info ));
}
}
/**
* Gets the port name
* @return The port name
*/
QString
MidiPort::getPortName()
{
return m_Info.getName();
}
/**
* Sets the port name
* @param newName The new port name
*/
void
MidiPort::setPortName( QString const& newName )
{
m_Info.setName(newName);
applyPortInfo();
}
/**
* Gets the port number
* @return The port number
*/
int
MidiPort::getPortId()
{
return m_Info.getPort();
}
/**
* Gets the port capabilities
* @return The capabilities bitmap
* @see PortInfo::getCapability()
*/
unsigned int
MidiPort::getCapability()
{
return m_Info.getCapability();
}
/**
* Sets the port capabilities
* @param newValue The capabilities bitmap
* @see PortInfo::setCapability()
*/
void
MidiPort::setCapability(unsigned int newValue)
{
m_Info.setCapability(newValue);
applyPortInfo();
}
/**
* Gets the port type
* @return The port type bitmap
* @see PortInfo::getType()
*/
unsigned int
MidiPort::getPortType()
{
return m_Info.getType();
}
/**
* Sets the port type bitmap
* @param newValue The port type flags bitmap
* @see PortInfo::setType()
*/
void
MidiPort::setPortType( unsigned int newValue)
{
m_Info.setType( newValue );
applyPortInfo();
}
/**
* Gets the MIDI channels
* @return The MIDI channels
*/
int
MidiPort::getMidiChannels()
{
return m_Info.getMidiChannels();
}
/**
* Sets the MIDI channels
* @param newValue The MIDI channels
*/
void
MidiPort::setMidiChannels(int newValue)
{
m_Info.setMidiChannels( newValue );
applyPortInfo();
}
/**
* Gets the MIDI voices
* @return The MIDI voices
*/
int
MidiPort::getMidiVoices()
{
return m_Info.getMidiVoices();
}
/**
* Sets the MIDI voices
* @param newValue The MIDI voices
*/
void
MidiPort::setMidiVoices(int newValue)
{
m_Info.setMidiVoices( newValue );
applyPortInfo();
}
/**
* Gets the synth voices
* @return The synth voices
*/
int
MidiPort::getSynthVoices()
{
return m_Info.getSynthVoices();
}
/**
* Sets the synth voices
* @param newValue The synth voices
*/
void
MidiPort::setSynthVoices(int newValue)
{
m_Info.setSynthVoices( newValue );
applyPortInfo();
}
/**
* Gets the timestamping mode
* @return The timestamping mode
*/
bool
MidiPort::getTimestamping()
{
return m_Info.getTimestamping();
}
/**
* Gets the timestamp real mode
* @return The timestamp real mode
*/
bool
MidiPort::getTimestampReal()
{
return m_Info.getTimestampReal();
}
/**
* Gets the timestamp queue number
* @return The timestamp queue number
*/
int
MidiPort::getTimestampQueue()
{
return m_Info.getTimestampQueue();
}
/**
* Sets the timestamping mode
* @param value The timestamping mode
*/
void
MidiPort::setTimestamping(bool value)
{
m_Info.setTimestamping(value);
applyPortInfo();
}
/**
* Sets the timestamp real mode
* @param value The timestamp real mode
*/
void
MidiPort::setTimestampReal(bool value)
{
m_Info.setTimestampReal(value);
applyPortInfo();
}
/**
* Sets the timestamp queue number
* @param queueId The queue number
*/
void
MidiPort::setTimestampQueue(int queueId)
{
m_Info.setTimestampQueue(queueId);
applyPortInfo();
}
/**
* Attach the port to a MidiClient instance
* @param seq A MidiClient object pointer
*/
void
MidiPort::attach( MidiClient* seq )
{
if (!m_Attached && (seq != nullptr)) {
m_MidiClient = seq;
m_MidiClient->portAttach(this);
m_Attached = true;
Q_EMIT attached(this);
}
}
/**
* Detach the port from any MidiClient instance previously attached
*/
void
MidiPort::detach()
{
if (m_Attached && (m_MidiClient != nullptr)) {
m_MidiClient->portDetach(this);
m_Attached = false;
Q_EMIT detached(this);
}
}
/**
* Update the subscribers list in the PortInfo member
*/
void
MidiPort::updateSubscribers()
{
m_Info.readSubscribers(m_MidiClient);
}
/**
* Gets the list of read subscribers
* @return The list of read subscribers
*/
PortInfoList
MidiPort::getReadSubscribers()
{
const SubscribersList subs(m_Info.getReadSubscribers());
PortInfoList lst;
SubscribersList::ConstIterator it;
for(it = subs.constBegin(); it != subs.constEnd(); ++it) {
Subscriber s = *it;
int client = s.getAddr()->client;
if ((client != SND_SEQ_CLIENT_SYSTEM) && (client != m_Info.getClient())) {
int port = s.getAddr()->port;
PortInfo p(m_MidiClient, client, port);
if ((p.getCapability() & SND_SEQ_PORT_CAP_NO_EXPORT) == 0) {
p.setClientName(m_MidiClient->getClientName(client));
lst << p;
}
}
}
return lst;
}
/**
* Gets the list of write subscribers
* @return The list of write subscribers
*/
PortInfoList
MidiPort::getWriteSubscribers()
{
const SubscribersList subs(m_Info.getWriteSubscribers());
PortInfoList lst;
SubscribersList::ConstIterator it;
for(it = subs.constBegin(); it != subs.constEnd(); ++it) {
Subscriber s = *it;
int client = s.getAddr()->client;
if ((client != SND_SEQ_CLIENT_SYSTEM) && (client != m_Info.getClient())) {
int port = s.getAddr()->port;
PortInfo p(m_MidiClient, client, port);
if ((p.getCapability() & SND_SEQ_PORT_CAP_NO_EXPORT) == 0) {
p.setClientName(m_MidiClient->getClientName(client));
lst << p;
}
}
}
return lst;
}
/**
* Checks if the provided address is included in the port list
* @param addr ALSA address record pointer
* @param lst List of port information containers
* @return True if the address is found
*/
bool
MidiPort::containsAddress(const snd_seq_addr_t* addr, const PortInfoList& lst)
{
PortInfoList::ConstIterator i;
for( i = lst.begin(); i != lst.end(); ++i) {
PortInfo p = *i;
if ((p.getAddr()->client == addr->client) &&
(p.getAddr()->port == addr->port)) {
return true;
}
}
return false;
}
/**
* Update the write subscriptions
* @param ports List of writable ports to be subscribed
*/
void
MidiPort::updateConnectionsTo(const PortInfoList& ports)
{
PortInfoList subs(getReadSubscribers());
PortInfoList::ConstIterator i;
for (i = subs.constBegin(); i != subs.constEnd(); ++i) {
PortInfo s = *i;
if (!containsAddress(s.getAddr(), ports)) {
unsubscribeTo(s.getAddr());
}
}
for (i = ports.constBegin(); i != ports.constEnd(); ++i) {
PortInfo p = *i;
if (!containsAddress(p.getAddr(), subs)) {
subscribeTo(&p);
}
}
}
/**
* Update the read susbcriptions
* @param ports List of readable ports to be subscribed
*/
void
MidiPort::updateConnectionsFrom(const PortInfoList& ports)
{
PortInfoList subs(getWriteSubscribers());
PortInfoList::ConstIterator i;
for (i = subs.constBegin(); i != subs.constEnd(); ++i) {
PortInfo s = *i;
if (!containsAddress(s.getAddr(), ports)) {
unsubscribeFrom(s.getAddr());
}
}
for (i = ports.constBegin(); i != ports.constEnd(); ++i) {
PortInfo p = *i;
if (!containsAddress(p.getAddr(), subs)) {
subscribeFrom(&p);
}
}
}
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/alsa/alsatimer.cpp 0000644 0001750 0001750 00000073504 14541630232 017615 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include "errorcheck.h"
#include
#include
#include
#include
#include
/**
* @file alsatimer.cpp
* Implementation of classes managing ALSA Timers
*/
namespace drumstick {
namespace ALSA {
/**
* @addtogroup ALSATimer
* @{
*
* Timers provide periodic time events to applications, and also to the ALSA
* sequencer.
*
* There are two mechanisms to deliver the timer events. To use the callback
* mechanism, a class must be derived from TimerEventHandler, and a instance
* of the derived class must be assigned to the Timer instance using
* Timer::setHandler(). If the handler is not assigned, then the Timer instance
* will generate the signal Timer::timerExpired().
*
* Classes:
*
* TimerInfo: ALSA Timer information container.
*
* This class is used to hold properties about ALSA Timers.
*
* TimerId: ALSA Timer identifier container.
*
* This class provides an unique identifier for a Timer.
*
* TimerGlobalInfo: Global timer information container.
*
* This class provides global timer parameters.
*
* TimerQuery: ALSA Timer inquiry helper.
*
* This class provides a mechanism to enumerate the available system timers.
*
* TimerParams: ALSA Timer parameters container.
*
* This class provides several parameters about a Timer.
*
* TimerStatus: ALSA Timer status container.
*
* This class provides some status information about a Timer.
*
* TimerEventHandler: ALSA Timer events handler.
*
* This abstract class is used to define an interface that other class can
* implement to receive timer events.
*
* Timer: ALSA Timer management.
*
* This class represents an ALSA timer object.
*
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___timer.html
* @}
*/
/**
* Constructor
*/
TimerInfo::TimerInfo()
{
snd_timer_info_malloc(&m_Info);
}
/**
* Cosntructor
* @param other ALSA timer info object pointer
*/
TimerInfo::TimerInfo(const snd_timer_info_t *other)
{
snd_timer_info_malloc(&m_Info);
snd_timer_info_copy(m_Info, other);
}
/**
* Copy constructor
* @param other Existing TimerInfo object reference
*/
TimerInfo::TimerInfo(const TimerInfo& other)
{
snd_timer_info_malloc(&m_Info);
snd_timer_info_copy(m_Info, other.m_Info);
}
/**
* Destructor
*/
TimerInfo::~TimerInfo()
{
snd_timer_info_free(m_Info);
}
/**
* Copy the current object
* @return Pointer to the new object
*/
TimerInfo*
TimerInfo::clone()
{
return new TimerInfo(m_Info);
}
/**
* Assignment operator
* @param other Existing TimerInfo object reference
* @return a reference of this object
*/
TimerInfo&
TimerInfo::operator=(const TimerInfo& other)
{
if (this == &other)
return *this;
snd_timer_info_copy(m_Info, other.m_Info);
return *this;
}
/**
* Check if the timer is slave (depends on another device)
* @return True if the timer is slave
*/
bool
TimerInfo::isSlave()
{
return (snd_timer_info_is_slave(m_Info) != 0);
}
/**
* Gets the card number
* @return Card number
*/
int
TimerInfo::getCard()
{
return snd_timer_info_get_card(m_Info);
}
/**
* Gets the string identifier
* @return String identifier
*/
QString
TimerInfo::getId()
{
return QString(snd_timer_info_get_id(m_Info));
}
/**
* Gets the timer name
* @return Timer name
*/
QString
TimerInfo::getName()
{
return QString(snd_timer_info_get_name(m_Info));
}
/**
* Gets the timer resolution (timer period in nanoseconds)
* @return Timer resolution in nanos
*/
long
TimerInfo::getResolution()
{
return snd_timer_info_get_resolution(m_Info);
}
/**
* Gets the timer frequency in Hz
* @return Timer frequency in Hz
*/
long
TimerInfo::getFrequency()
{
long res = getResolution();
if (res > 0)
{
return 1000000000L / res;
}
return 0;
}
/**
* Gets the size of the ALSA timer info object
* @return Size of the ALSA object
*/
int
TimerInfo::getSizeOfInfo() const
{
return snd_timer_info_sizeof();
}
/**
* Gets the maximum timer ticks
* @return Maximum timer ticks
* @deprecated
*/
long
TimerInfo::getTicks()
{
return snd_timer_info_get_ticks(m_Info);
}
/**
* Constructor
*/
TimerId::TimerId()
{
snd_timer_id_malloc(&m_Info);
}
/**
* Constructor
* @param other ALSA timer ID object pointer
*/
TimerId::TimerId(const snd_timer_id_t *other)
{
snd_timer_id_malloc(&m_Info);
snd_timer_id_copy(m_Info, other);
if (getCard() < 0)
setCard(0);
if (getDevice() < 0)
setDevice(0);
if (getSubdevice() < 0)
setSubdevice(0);
}
/**
* Copy constructor
* @param other Existing TimerId object reference
*/
TimerId::TimerId(const TimerId& other)
{
snd_timer_id_malloc(&m_Info);
snd_timer_id_copy(m_Info, other.m_Info);
if (getCard() < 0)
setCard(0);
if (getDevice() < 0)
setDevice(0);
if (getSubdevice() < 0)
setSubdevice(0);
}
/**
* Constructor
* @param cls Class
* @param scls Subclass
* @param card Card
* @param dev Device
* @param sdev Subdevice
*/
TimerId::TimerId(int cls, int scls, int card, int dev, int sdev)
{
snd_timer_id_malloc(&m_Info);
setClass(cls);
setSlaveClass(scls);
setCard(card);
setDevice(dev);
setSubdevice(sdev);
}
/**
* Destructor
*/
TimerId::~TimerId()
{
snd_timer_id_free(m_Info);
}
/**
* Copy the object
* @return Pointer to the new object
*/
TimerId*
TimerId::clone()
{
return new TimerId(m_Info);
}
/**
* Assignment operator
* @param other Existing TimerId object reference
* @return This object
*/
TimerId&
TimerId::operator=(const TimerId& other)
{
if (this == &other)
return *this;
snd_timer_id_copy(m_Info, other.m_Info);
if (getCard() < 0)
setCard(0);
if (getDevice() < 0)
setDevice(0);
if (getSubdevice() < 0)
setSubdevice(0);
return *this;
}
/**
* Set the class identifier. Existing classes:
*
* - SND_TIMER_CLASS_SLAVE: slave timer
* - SND_TIMER_CLASS_GLOBAL: global timer
* - SND_TIMER_CLASS_CARD: card timer
* - SND_TIMER_CLASS_PCM: PCM timer
*
* @param devclass Class identifier.
*/
void
TimerId::setClass(int devclass)
{
snd_timer_id_set_class(m_Info, devclass);
}
/**
* Gets the class identifier.
* @return Class identifier
* @see setClass()
*/
int
TimerId::getClass()
{
return snd_timer_id_get_class(m_Info);
}
/**
* Sets the Slave class
* @param devsclass Slave class
*/
void
TimerId::setSlaveClass(int devsclass)
{
snd_timer_id_set_sclass(m_Info, devsclass);
}
/**
* Gets the slave class
* @return Slave class
*/
int
TimerId::getSlaveClass()
{
return snd_timer_id_get_sclass(m_Info);
}
/**
* Sets the card number
* @param card Card number
*/
void
TimerId::setCard(int card)
{
snd_timer_id_set_card(m_Info, card);
}
/**
* Gets the card number
* @return Card number
*/
int
TimerId::getCard()
{
return snd_timer_id_get_card(m_Info);
}
/**
* Sets the device number
* @param device Device number
*/
void
TimerId::setDevice(int device)
{
snd_timer_id_set_device(m_Info, device);
}
/**
* Gets the device number
* @return Device number
*/
int
TimerId::getDevice()
{
return snd_timer_id_get_device(m_Info);
}
/**
* Sets the subdevice number
* @param subdevice Subdevice number
*/
void
TimerId::setSubdevice(int subdevice)
{
snd_timer_id_set_subdevice (m_Info, subdevice);
}
/**
* Gets the subdevice number
* @return Subdevice number
*/
int
TimerId::getSubdevice()
{
return snd_timer_id_get_subdevice(m_Info);
}
/**
* Gets the size of the ALSA timer ID object
* @return Size of the ALSA object
*/
int
TimerId::getSizeOfInfo() const
{
return snd_timer_id_sizeof();
}
/**
* Constructor
* @param deviceName Device name, usually "hw"
* @param openMode Open mode (unknown values)
*/
TimerQuery::TimerQuery(const QString& deviceName, int openMode)
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_query_open( &m_Info,
deviceName.toLocal8Bit().data(),
openMode ));
readTimers();
}
/**
* Constructor
* @param deviceName Device name, usually "hw"
* @param openMode Open mode (unknown values)
* @param conf ALSA configuration object pointer
*/
TimerQuery::TimerQuery( const QString& deviceName, int openMode,
snd_config_t* conf )
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_query_open_lconf( &m_Info,
deviceName.toLocal8Bit().data(),
openMode, conf ));
readTimers();
}
/**
* Destructor
*/
TimerQuery::~TimerQuery()
{
freeTimers();
snd_timer_query_close(m_Info);
}
/**
* Enumerate the available timers storing the results into an internal list
*/
void
TimerQuery::readTimers()
{
TimerId tid;
snd_timer_id_set_class(tid.m_Info, SND_TIMER_CLASS_NONE);
for(;;)
{
int rc = snd_timer_query_next_device(m_Info, tid.m_Info);
if ((rc < 0) || (tid.getClass() < 0)) {
break;
}
m_timers.append(tid);
}
}
/**
* Release the internal list of timers
*/
void
TimerQuery::freeTimers()
{
m_timers.clear();
}
/**
* Get a TimerGlobalInfo object
* @return TimerGlobalInfo object reference
*/
TimerGlobalInfo&
TimerQuery::getGlobalInfo()
{
snd_timer_query_info(m_Info, m_GlobalInfo.m_Info);
return m_GlobalInfo;
}
/**
* Sets the global parameters
* @param params Pointer to an ALSA timer global parameters object
*/
void
TimerQuery::setGlobalParams(snd_timer_gparams_t* params)
{
snd_timer_query_params(m_Info, params);
}
/**
* Gets the global timer parameters
* @param params Pointer to an ALSA timer global parameters object
*/
void
TimerQuery::getGlobalParams(snd_timer_gparams_t* params)
{
snd_timer_query_params(m_Info, params);
}
/**
* Gets the global timer status
* @param status Pointer to an ALSA timer global status object
*/
void
TimerQuery::getGlobalStatus(snd_timer_gstatus_t *status)
{
snd_timer_query_status(m_Info, status);
}
/**
* Default constructor
*/
TimerGlobalInfo::TimerGlobalInfo()
{
snd_timer_ginfo_malloc(&m_Info);
}
/**
* Constructor
* @param other ALSA global info object pointer
*/
TimerGlobalInfo::TimerGlobalInfo(const snd_timer_ginfo_t* other)
{
snd_timer_ginfo_malloc(&m_Info);
snd_timer_ginfo_copy(m_Info, other);
}
/**
* Copy constructor
* @param other Existing TimerGlobalInfo object reference
*/
TimerGlobalInfo::TimerGlobalInfo(const TimerGlobalInfo& other)
{
snd_timer_ginfo_malloc(&m_Info);
snd_timer_ginfo_copy(m_Info, other.m_Info);
}
/**
* Destructor
*/
TimerGlobalInfo::~TimerGlobalInfo()
{
snd_timer_ginfo_free(m_Info);
}
/**
* Copy the current object
* @return Pointer to the new object
*/
TimerGlobalInfo*
TimerGlobalInfo::clone()
{
return new TimerGlobalInfo(m_Info);
}
/**
* Assignment operator
* @param other Existing TimerGlobalInfo object reference
* @return This object
*/
TimerGlobalInfo&
TimerGlobalInfo::operator=(const TimerGlobalInfo& other)
{
if (this == &other)
return *this;
snd_timer_ginfo_copy(m_Info, other.m_Info);
return *this;
}
/**
* Sets the timer identifier
* @param tid TimerId object reference
*/
void
TimerGlobalInfo::setTimerId(const TimerId& tid)
{
m_Id = tid;
snd_timer_ginfo_set_tid (m_Info, m_Id.m_Info);
}
/**
* Gets the timer identifier
* @return TimerId object reference
*/
TimerId&
TimerGlobalInfo::getTimerId()
{
m_Id = TimerId(snd_timer_ginfo_get_tid (m_Info));
return m_Id;
}
/**
* Gets the flags
* @return Undocumented flags
*/
unsigned int
TimerGlobalInfo::getFlags()
{
return snd_timer_ginfo_get_flags (m_Info);
}
/**
* Gets the card number
* @return Card number
*/
int
TimerGlobalInfo::getCard()
{
return snd_timer_ginfo_get_card (m_Info);
}
/**
* Gets the timer ID string
* @return Timer ID string
*/
QString
TimerGlobalInfo::getId()
{
return QString(snd_timer_ginfo_get_id (m_Info));
}
/**
* Gets the timer name
* @return Timer name
*/
QString
TimerGlobalInfo::getName()
{
return QString(snd_timer_ginfo_get_name (m_Info));
}
/**
* Gets the timer resolution in ns
* @return Timer resolution in ns
*/
unsigned long
TimerGlobalInfo::getResolution()
{
return snd_timer_ginfo_get_resolution (m_Info);
}
/**
* Gets timer minimal resolution in ns
* @return Minimal resolution in ns
*/
unsigned long
TimerGlobalInfo::getMinResolution()
{
return snd_timer_ginfo_get_resolution_min (m_Info);
}
/**
* Gets timer maximal resolution in ns
* @return Maximal resolution in ns
*/
unsigned long
TimerGlobalInfo::getMaxResolution()
{
return snd_timer_ginfo_get_resolution_max(m_Info);
}
/**
* Gets current timer clients
* @return Current clients
*/
unsigned int
TimerGlobalInfo::getClients()
{
return snd_timer_ginfo_get_clients(m_Info);
}
/**
* Gets the size of the ALSA timer global info object
* @return Size of the ALSA object
*/
int
TimerGlobalInfo::getSizeOfInfo() const
{
return snd_timer_ginfo_sizeof();
}
/**
* Default constructor
*/
TimerParams::TimerParams()
{
snd_timer_params_malloc (&m_Info);
}
/**
* Constructor
* @param other Pointer to an ALSA timer parameters object
*/
TimerParams::TimerParams(const snd_timer_params_t *other)
{
snd_timer_params_malloc (&m_Info);
snd_timer_params_copy (m_Info, other);
}
/**
* Copy constructor
* @param other Existing TimerParams object reference
*/
TimerParams::TimerParams(const TimerParams& other)
{
snd_timer_params_malloc (&m_Info);
snd_timer_params_copy (m_Info, other.m_Info);
}
/**
* Destructor
*/
TimerParams::~TimerParams()
{
snd_timer_params_free (m_Info);
}
/**
* Copy the current object
* @return Pointer to the new object
*/
TimerParams*
TimerParams::clone()
{
return new TimerParams(m_Info);
}
/**
* Assignment operator
* @param other Existing TimerParams object reference
* @return This object
*/
TimerParams&
TimerParams::operator=(const TimerParams& other)
{
if (this == &other)
return *this;
snd_timer_params_copy (m_Info, other.m_Info);
return *this;
}
/**
* Sets the automatic start flag
* @param auto_start Value for the automatic start flag
*/
void
TimerParams::setAutoStart(bool auto_start)
{
snd_timer_params_set_auto_start (m_Info, auto_start ? 1 : 0);
}
/**
* Gets the automatic start flag
* @return True if the timer starts automatically
*/
bool
TimerParams::getAutoStart()
{
return (snd_timer_params_get_auto_start (m_Info) != 0);
}
/**
* Sets the exclusive flag
* @param exclusive True if the timer has the exclusive flag
*/
void
TimerParams::setExclusive(bool exclusive)
{
snd_timer_params_set_exclusive (m_Info, exclusive ? 1 : 0);
}
/**
* Gets the timer's exclusive flag
* @return True if the timer has the exclusive flag
*/
bool
TimerParams::getExclusive()
{
return (snd_timer_params_get_exclusive (m_Info) != 0);
}
/**
* Sets the timer early event
* @param early_event Timer early event
*/
void
TimerParams::setEarlyEvent(bool early_event)
{
snd_timer_params_set_early_event (m_Info, early_event ? 1 : 0);
}
/**
* Gets the timer early event
* @return Timer early event
*/
bool
TimerParams::getEarlyEvent()
{
return (snd_timer_params_get_early_event (m_Info) != 0);
}
/**
* Sets the timer ticks
* @param ticks Timer ticks
*/
void
TimerParams::setTicks(long ticks)
{
snd_timer_params_set_ticks (m_Info, ticks);
}
/**
* Gets the timer ticks
* @return Timer ticks
*/
long
TimerParams::getTicks()
{
return snd_timer_params_get_ticks (m_Info);
}
/**
* Sets the queue size (32-1024)
* @param queue_size Queue size
*/
void
TimerParams::setQueueSize(long queue_size)
{
snd_timer_params_set_queue_size (m_Info, queue_size);
}
/**
* Gets the queue size
* @return Queue size
*/
long
TimerParams::getQueueSize()
{
return snd_timer_params_get_queue_size (m_Info);
}
/**
* Sets the event filter
* @param filter Event filter
*/
void
TimerParams::setFilter(unsigned int filter)
{
snd_timer_params_set_filter (m_Info, filter);
}
/**
* Gets the event filter
* @return Event filter
*/
unsigned int
TimerParams::getFilter()
{
return snd_timer_params_get_filter (m_Info);
}
/**
* Gets the size of the ALSA timer parameters object
* @return Size of the ALSA object
*/
int
TimerParams::getSizeOfInfo() const
{
return snd_timer_params_sizeof();
}
/**
* Default constructor
*/
TimerStatus::TimerStatus()
{
snd_timer_status_malloc (&m_Info);
}
/**
* Constructor
* @param other Pointer to an existing ALSA timer status object
*/
TimerStatus::TimerStatus(const snd_timer_status_t *other)
{
snd_timer_status_malloc (&m_Info);
snd_timer_status_copy (m_Info, other);
}
/**
* Copy constructor
* @param other Existing TimerStatus object reference
*/
TimerStatus::TimerStatus(const TimerStatus& other)
{
snd_timer_status_malloc (&m_Info);
snd_timer_status_copy (m_Info, other.m_Info);
}
/**
* Destructor
*/
TimerStatus::~TimerStatus()
{
snd_timer_status_free (m_Info);
}
/**
* Copy the current object
* @return Pointer to the new object
*/
TimerStatus*
TimerStatus::clone()
{
return new TimerStatus(m_Info);
}
/**
* Assignment operator
* @param other Existing TimerStatus object reference
* @return This object
*/
TimerStatus&
TimerStatus::operator=(const TimerStatus& other)
{
if (this == &other)
return *this;
snd_timer_status_copy (m_Info, other.m_Info);
return *this;
}
/**
* Gets the high resolution time-stamp
* @return High resolution time-stamp
*/
snd_htimestamp_t
TimerStatus::getTimestamp()
{
return snd_timer_status_get_timestamp (m_Info);
}
/**
* Gets the resolution in us
* @return Resolution in us
*/
long
TimerStatus::getResolution()
{
return snd_timer_status_get_resolution (m_Info);
}
/**
* Gets the master tick lost count
* @return Master tick lost count
*/
long
TimerStatus::getLost()
{
return snd_timer_status_get_lost (m_Info);
}
/**
* Gets the overrun count
* @return Overrun count
*/
long
TimerStatus::getOverrun()
{
return snd_timer_status_get_overrun (m_Info);
}
/**
* Gets the count of used queue elements
* @return Count of used queue elements
*/
long
TimerStatus::getQueue()
{
return snd_timer_status_get_queue (m_Info);
}
/**
* Gets the size of the ALSA timer status object
* @return Size of the ALSA object
*/
int
TimerStatus::getSizeOfInfo() const
{
return snd_timer_status_sizeof();
}
/**
* Constructor.
* Open flags can be a combination of the following constants:
*
* - SND_TIMER_OPEN_NONBLOCK: non-blocking behavior
* - SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification
*
* @param deviceName Name of the device
* @param openMode Open mode flags bitmap
* @param parent Optional parent object
*/
Timer::Timer( const QString& deviceName, int openMode, QObject* parent )
: QObject(parent),
m_asyncHandler(nullptr),
m_handler(nullptr),
m_thread(nullptr),
m_deviceName(deviceName)
{
DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open( &m_Info, m_deviceName.toLocal8Bit().data(),
openMode ));
}
/**
* Constructor.
* Open flags can be a combination of the following constants:
*
* - SND_TIMER_OPEN_NONBLOCK: non-blocking behavior
* - SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification
*
* @param deviceName Name of the device
* @param openMode Open mode flags bitmap
* @param conf ALSA configuration object pointer
* @param parent Optional parent object
*/
Timer::Timer( const QString& deviceName, int openMode, snd_config_t* conf,
QObject* parent )
: QObject(parent),
m_asyncHandler(nullptr),
m_handler(nullptr),
m_thread(nullptr),
m_deviceName(deviceName)
{
DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open_lconf( &m_Info,
m_deviceName.toLocal8Bit().data(),
openMode, conf ));
}
/**
* Constructor
* Open flags can be a combination of the following constants:
*
* - SND_TIMER_OPEN_NONBLOCK: non-blocking behavior
* - SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification
*
* @param id TimerId object reference
* @param openMode Open mode flags bitmap
* @param parent Optional parent object
*/
Timer::Timer( TimerId& id, int openMode, QObject* parent )
: QObject(parent),
m_asyncHandler(nullptr),
m_handler(nullptr),
m_thread(nullptr)
{
m_deviceName = QString("hw:CLASS=%1,SCLASS=%2,CARD=%3,DEV=%4,SUBDEV=%5")
.arg(id.getClass())
.arg(id.getSlaveClass())
.arg(id.getCard())
.arg(id.getDevice())
.arg(id.getSubdevice());
DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open( &m_Info,
m_deviceName.toLocal8Bit().data(),
openMode ));
}
/**
* Constructor.
* Open flags can be a combination of the following constants:
*
* - SND_TIMER_OPEN_NONBLOCK: non-blocking behavior
* - SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification
*
* @param cls Class
* @param scls Subclass
* @param card Card
* @param dev Device
* @param sdev Subdevice
* @param openMode Open mode flags bitmap
* @param parent Optional parent object
*/
Timer::Timer( int cls, int scls, int card, int dev, int sdev,
int openMode, QObject* parent )
: QObject(parent),
m_asyncHandler(nullptr),
m_handler(nullptr),
m_thread(nullptr)
{
m_deviceName = QString("hw:CLASS=%1,SCLASS=%2,CARD=%3,DEV=%4,SUBDEV=%5")
.arg(cls)
.arg(scls)
.arg(card)
.arg(dev)
.arg(sdev);
DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open( &m_Info,
m_deviceName.toLocal8Bit().data(),
openMode ));
}
/**
* Destructor.
*/
Timer::~Timer()
{
stopEvents();
if (m_thread != nullptr)
delete m_thread;
DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_close(m_Info));
}
/**
* Adds an asynchronous timer handler function.
* @param callback Function handler
* @param private_data Any data that will be passed to the callback
*/
void
Timer::addAsyncTimerHandler(snd_async_callback_t callback, void *private_data)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_async_add_timer_handler(&m_asyncHandler, m_Info, callback, private_data));
}
/**
* Gets the ALSA timer handle
* @return ALSA timer handle
*/
snd_timer_t*
Timer::getTimerHandle()
{
return snd_async_handler_get_timer(m_asyncHandler);
}
/**
* Gets the count of poll descriptors
* @return Count of poll descriptors
*/
int
Timer::getPollDescriptorsCount()
{
return snd_timer_poll_descriptors_count(m_Info);
}
/**
* Gets poll descriptors
* @param pfds Pointer to a pollfd array
* @param space Number of pollfd elements available
*/
void
Timer::pollDescriptors(struct pollfd *pfds, unsigned int space)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_poll_descriptors(m_Info, pfds, space));
}
/**
* Gets returned events from poll descriptors
* @param pfds Pointer to a pollfd array
* @param nfds Number of pollfd elements available
* @param revents Returned events
*/
void
Timer::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_poll_descriptors_revents(m_Info, pfds, nfds, revents));
}
/**
* Gets the timer info object
* @return TimerInfo object reference
*/
TimerInfo&
Timer::getTimerInfo()
{
snd_timer_info (m_Info, m_TimerInfo.m_Info);
return m_TimerInfo;
}
/**
* Sets the timer parameters
* @param params TimerParams object reference
*/
void
Timer::setTimerParams(const TimerParams& params)
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_params(m_Info, params.m_Info) );
}
/**
* Gets the timer status
* @return TimerStatus object reference
*/
TimerStatus&
Timer::getTimerStatus()
{
DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_status(m_Info, m_TimerStatus.m_Info) );
return m_TimerStatus;
}
/**
* Start rolling the timer
*/
void
Timer::start()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_start(m_Info));
}
/**
* Stop rolling the timer
*/
void
Timer::stop()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_stop(m_Info));
}
/**
* Continue rolling the timer
*/
void
Timer::continueRunning()
{
DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_continue(m_Info));
}
/**
* Read bytes from the timer handle
* @param buffer Buffer to store the input bytes
* @param size Input buffer size in bytes
* @return Bytes read from the timer
*/
ssize_t
Timer::read(void *buffer, size_t size)
{
return snd_timer_read(m_Info, buffer, size);
}
/**
* Internal function to deliver the timer events using one of the two available
* methods:
*
* - TimerEventHandler instance pointer provided in Timer::setHandler()
* - A signal Timer::timerExpired() is emitted, otherwise
*
*/
void
Timer::doEvents()
{
snd_timer_tread_t tr;
while ( read(&tr, sizeof(tr)) == sizeof(tr) ) {
int msecs = ((tr.tstamp.tv_sec - m_last_time.tv_sec) * 1000) +
round((tr.tstamp.tv_nsec - m_last_time.tv_nsec) / 1000000.0);
m_last_time = tr.tstamp;
if ( m_handler != nullptr )
m_handler->handleTimerEvent(tr.val, msecs);
else
Q_EMIT timerExpired(tr.val, msecs);
}
}
/**
* Starts the events dispatching thread
*/
void Timer::startEvents()
{
m_last_time = getTimerStatus().getTimestamp();
if (m_thread == nullptr) {
m_thread = new TimerInputThread(this, 500);
m_thread->start();
}
}
/**
* Stops the events dispatching thread
*/
void Timer::stopEvents()
{
int counter = 0;
if (m_thread != nullptr) {
m_thread->stop();
while (!m_thread->wait(500) && (counter < 10)) {
counter++;
}
if (!m_thread->isFinished()) {
m_thread->terminate();
}
delete m_thread;
}
}
/**
* Check and return the best available global TimerId in the system, meaning
* the timer with higher frequency (or lesser period, resolution).
* @return A TimerId object
* @since 0.3.0
*/
TimerId
Timer::bestGlobalTimerId()
{
TimerId id;
snd_timer_t* timer;
snd_timer_info_t* info;
long res, best_res = LONG_MAX;
char timername[64];
int test_devs[] = {
SND_TIMER_GLOBAL_SYSTEM
, SND_TIMER_GLOBAL_RTC
#ifdef SND_TIMER_GLOBAL_HPET
, SND_TIMER_GLOBAL_HPET
#endif
#ifdef SND_TIMER_GLOBAL_HRTIMER
, SND_TIMER_GLOBAL_HRTIMER
#endif
};
int max_global_timers = sizeof(test_devs)/sizeof(int);
int clas = SND_TIMER_CLASS_GLOBAL;
int scls = SND_TIMER_SCLASS_NONE;
int card = 0;
int dev = SND_TIMER_GLOBAL_SYSTEM;
int sdev = 0;
int err = 0;
int is_slave = 0;
int i;
snd_timer_info_alloca(&info);
// default system timer
id.setClass(clas);
id.setSlaveClass(scls);
id.setCard(card);
id.setDevice(dev);
id.setSubdevice(sdev);
// select a non slave timer with the lowest resolution value
for( i = 0; i < max_global_timers; ++i )
{
dev = test_devs[i];
sprintf( timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i",
clas, scls, card, dev, sdev );
err = snd_timer_open(&timer, timername, SND_TIMER_OPEN_NONBLOCK);
if (err < 0) continue;
err = snd_timer_info(timer, info);
if (err == 0) {
is_slave = snd_timer_info_is_slave(info);
res = snd_timer_info_get_resolution(info);
if ((is_slave == 0) && (best_res > res)) {
best_res = res;
id.setDevice(dev);
}
}
snd_timer_close(timer);
}
return id;
}
/**
* Check and return the best available global Timer in the system, meaning
* the timer with higher frequency (or lesser period, resolution).
* @param openMode Open mode flags
* @param parent Optional parent object
* @return A new Timer instance pointer
*/
Timer*
Timer::bestGlobalTimer(int openMode, QObject* parent)
{
TimerId id = bestGlobalTimerId();
return new Timer(id, openMode, parent);
}
/**
* Loop reading and dispatching timer events.
*/
void
Timer::TimerInputThread::run()
{
int err, count;
struct pollfd *fds;
if (m_timer == nullptr) return;
count = m_timer->getPollDescriptorsCount();
fds = (pollfd *) calloc(count, sizeof(struct pollfd));
if (fds == nullptr) {
qWarning() << "allocation error!";
return;
}
fds->events = POLLIN;
fds->revents = 0;
try {
while (!stopped() && (m_timer != nullptr)) {
m_timer->pollDescriptors(fds, count);
if ((err = poll(fds, count, m_Wait)) < 0) {
qWarning() << "poll error " << err << "(" << strerror(err) << ")";
free(fds);
return;
}
if (err == 0) {
qWarning() << "timer time out";
free(fds);
return;
}
m_timer->doEvents();
}
} catch (...) {
qWarning() << "exception in input thread";
}
free(fds);
}
/**
* Returns the rolling state of the timer thread
* @return The stopped state
*/
bool
Timer::TimerInputThread::stopped()
{
QReadLocker locker(&m_mutex);
return m_Stopped;
}
/**
* Stop the thread
*/
void
Timer::TimerInputThread::stop()
{
QWriteLocker locker(&m_mutex);
m_Stopped = true;
}
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/alsa/playthread.cpp 0000644 0001750 0001750 00000014060 14541630232 017761 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
extern "C" {
#include
}
#include
#include
#include
#include
#include
/**
* @file playthread.cpp
* Implementation of a sequencer output thread
*/
/**
* @addtogroup PlayThread
* @{
* ALSA Sequencer easy playback functionality.
* SequencerOutputThread provides MIDI sequence playback.
*
* This is an abstract class that must be extended providing
* an implementation for the pure virtual methods:
* SequencerOutputThread::hasNext() and SequencerOutputThread::nextEvent()
* before using it for MIDI sequence playback. You can use any structure or
* class you prefer to store the SequencerEvent objects, but they must be
* provided ordered by time. A simplistic Song definition may be:
*
* @code
* typedef QList Song;
* @endcode
*
* Using this class is optional. You may prefer another mechanism to
* manage playback actions. This class uses a thread to manage the
* sequence playback as a background task.
* @}
*/
namespace drumstick {
namespace ALSA {
const int TIMEOUT = 100;
/**
* Constructor
* @param seq Existing MidiClient object pointer
* @param portId Numeric input/output port identifier
*/
SequencerOutputThread::SequencerOutputThread(MidiClient *seq, int portId)
: QThread(),
m_MidiClient(seq),
m_Queue(nullptr),
m_PortId(portId),
m_Stopped(false),
m_QueueId(0),
m_npfds(0),
m_pfds(nullptr)
{
if (m_MidiClient != nullptr) {
m_Queue = m_MidiClient->getQueue();
m_QueueId = m_Queue->getId();
}
}
/**
* Checks if stop has been requested
* @return True if stop has been requested
* @since 0.2.0
*/
bool
SequencerOutputThread::stopRequested()
{
QReadLocker locker(&m_mutex);
return m_Stopped;
}
/**
* Stops the playback task
*/
void
SequencerOutputThread::stop()
{
QWriteLocker locker(&m_mutex);
m_Stopped = true;
locker.unlock();
while (isRunning()) {
wait(TIMEOUT);
}
}
/**
* Sends an echo event, with the same PortId as sender and destination.
* @param tick Event schedule time in ticks.
*/
void
SequencerOutputThread::sendEchoEvent(int tick)
{
if (!stopRequested() && m_MidiClient != nullptr) {
SystemEvent ev(SND_SEQ_EVENT_ECHO);
ev.setSource(m_PortId);
ev.setDestination(m_MidiClient->getClientId(), m_PortId);
ev.scheduleTick(m_QueueId, tick, false);
sendSongEvent(&ev);
}
}
/**
* Sends a SequencerEvent
* @param ev SequencerEvent object pointer
*/
void
SequencerOutputThread::sendSongEvent(SequencerEvent* ev)
{
if (m_MidiClient != nullptr) {
while (!stopRequested() &&
(snd_seq_event_output_direct(m_MidiClient->getHandle(), ev->getHandle()) < 0)) {
poll(m_pfds, m_npfds, TIMEOUT);
}
}
}
/**
* Flush the ALSA output buffer.
*/
void
SequencerOutputThread::drainOutput()
{
if (!stopRequested() && m_MidiClient != nullptr) {
while (!stopRequested() && (snd_seq_drain_output(m_MidiClient->getHandle()) < 0)) {
poll(m_pfds, m_npfds, TIMEOUT);
}
}
}
/**
* Waits until the ALSA output queue is empty (all the events have been played.)
*/
void
SequencerOutputThread::syncOutput()
{
if (!stopRequested() && m_MidiClient != nullptr) {
m_MidiClient->synchronizeOutput();
}
}
/**
* Thread process loop
*/
void SequencerOutputThread::run()
{
if (m_MidiClient != nullptr) {
try {
unsigned int last_tick;
m_npfds = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLOUT);
m_pfds = (pollfd*) calloc(m_npfds, sizeof(pollfd));
snd_seq_poll_descriptors(m_MidiClient->getHandle(), m_pfds, m_npfds, POLLOUT);
last_tick = getInitialPosition();
if (last_tick == 0) {
m_Queue->start();
} else {
m_Queue->setTickPosition(last_tick);
m_Queue->continueRunning();
}
while (!stopRequested() && hasNext()) {
SequencerEvent* ev = nextEvent();
if (!stopRequested() && !SequencerEvent::isConnectionChange(ev)) {
sendSongEvent(ev);
}
if (getEchoResolution() > 0) {
while (!stopRequested() && (last_tick < ev->getTick())) {
last_tick += getEchoResolution();
sendEchoEvent(last_tick);
}
}
}
if (stopRequested()) {
m_Queue->clear();
Q_EMIT playbackStopped();
} else {
drainOutput();
syncOutput();
if (stopRequested())
Q_EMIT playbackStopped();
else
Q_EMIT playbackFinished();
}
m_Queue->stop();
} catch (...) {
qWarning("exception in output thread");
}
m_npfds = 0;
free(m_pfds);
m_pfds = nullptr;
}
}
/**
* Starts the playback thread
* @param priority Thread priority, default is InheritPriority
*/
void SequencerOutputThread::start( Priority priority )
{
QWriteLocker locker(&m_mutex);
m_Stopped = false;
QThread::start( priority );
}
} // namespace ALSA
} // namespace drumstick
drumstick-2.9.0/library/file/ 0000755 0001750 0001750 00000000000 14541630232 015116 5 ustar pedro pedro drumstick-2.9.0/library/file/drumstick-file-config.cmake 0000644 0001750 0001750 00000000143 14541630232 022303 0 ustar pedro pedro #include(CMakeFindDependencyMacro)
include(${CMAKE_CURRENT_LIST_DIR}/drumstick-file-targets.cmake)
drumstick-2.9.0/library/file/file.pro 0000644 0001750 0001750 00000002213 14541630232 016555 0 ustar pedro pedro TEMPLATE = lib
TARGET = drumstick-file
DESTDIR = ../../build/lib
DEPENDPATH += . ../include
INCLUDEPATH += . ../include
include (../../global.pri)
CONFIG += c++11 qt create_pc create_prl no_install_prl
DEFINES += drumstick_file_EXPORTS
QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS_HIDESYMS
QMAKE_PKGCONFIG_PREFIX = $$INSTALLBASE
QT -= gui
equals(QT_MAJOR_VERSION, 6) {
QT += core5compat
}
# Input
HEADERS += ../include/drumstick/macros.h \
../include/drumstick/rmid.h \
../include/drumstick/qsmf.h \
../include/drumstick/qwrk.h
SOURCES += rmid.cpp \
qsmf.cpp \
qwrk.cpp
static {
CONFIG += staticlib
DEFINES += DRUMSTICK_STATIC
}
macx:!static {
TARGET = drumstick-file
CONFIG += lib_bundle
FRAMEWORK_HEADERS.version = Versions
FRAMEWORK_HEADERS.files = $$HEADERS
FRAMEWORK_HEADERS.path = Headers/drumstick
QMAKE_BUNDLE_DATA += FRAMEWORK_HEADERS
#QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Frameworks/
QMAKE_SONAME_PREFIX = @rpath
QMAKE_TARGET_BUNDLE_PREFIX = net.sourceforge
QMAKE_BUNDLE = drumstick-file
QMAKE_INFO_PLIST = ../Info.plist.lib
}
drumstick-2.9.0/library/file/CMakeLists.txt 0000644 0001750 0001750 00000010545 14541630232 017663 0 ustar pedro pedro #[===========================================================================[
MIDI C++ Library
Copyright (C) 2005-2023 Pedro Lopez-Cabanillas
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 3 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, see .
#]===========================================================================]
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(drumstick-file_QTOBJ_SRCS
../include/drumstick/qsmf.h
../include/drumstick/qwrk.h
../include/drumstick/rmid.h
)
set(drumstick-file_HEADERS
../include/drumstick/macros.h
../include/drumstick/qsmf.h
../include/drumstick/qwrk.h
../include/drumstick/rmid.h
)
if(BUILD_FRAMEWORKS)
set_source_files_properties(${drumstick-file_HEADERS}
PROPERTIES MACOSX_PACKAGE_LOCATION Headers/drumstick
)
endif()
set(drumstick-file_SRCS
qsmf.cpp
qwrk.cpp
rmid.cpp
)
if (WIN32)
set(TARGET_DESCRIPTION ${Drumstick_DESCRIPTION})
set(TARGET_NAME drumstick-file)
set(TARGET_ORIGINAL_FILENAME libdrumstick-file.dll)
configure_file(${Drumstick_SOURCE_DIR}/versioninfo.rc.in versioninfo.rc @ONLY)
list(APPEND drumstick-file_SRCS versioninfo.rc)
endif()
if (QT_VERSION VERSION_LESS 5.15.0)
qt5_wrap_cpp(drumstick-file_MOC_SRCS ${drumstick-file_QTOBJ_SRCS})
else()
qt_wrap_cpp(drumstick-file_MOC_SRCS ${drumstick-file_QTOBJ_SRCS})
endif()
add_library(drumstick-file
${drumstick-file_MOC_SRCS}
${drumstick-file_SRCS}
${drumstick-file_HEADERS}
)
add_library(Drumstick::File ALIAS drumstick-file)
target_include_directories(drumstick-file PUBLIC
$
$
)
target_link_libraries(drumstick-file PRIVATE
Qt${QT_VERSION_MAJOR}::Core
)
target_compile_definitions(drumstick-file PRIVATE
QT_NO_SIGNALS_SLOTS_KEYWORDS
)
if (QT_VERSION VERSION_GREATER_EQUAL 6.0)
target_link_libraries(drumstick-file PRIVATE
Qt6::Core5Compat
)
endif()
if(STATIC_DRUMSTICK)
set_target_properties(drumstick-file PROPERTIES
STATIC_LIB "libdrumstick-file"
EXPORT_NAME File
)
else()
set_target_properties(drumstick-file PROPERTIES
VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
SOVERSION ${PROJECT_VERSION_MAJOR}
MACOSX_RPATH TRUE
EXPORT_NAME File
)
if(BUILD_FRAMEWORKS)
set_target_properties(drumstick-file PROPERTIES
FRAMEWORK ${BUILD_FRAMEWORKS}
FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
MACOSX_FRAMEWORK_IDENTIFIER "net.sourceforge.drumstick-file"
MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_SOURCE_DIR}/cmake_admin/CustomFrameworkInfo.plist.in"
)
endif()
endif()
install(TARGETS drumstick-file
EXPORT drumstick-file-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(FILES ${drumstick-file_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/drumstick)
install(EXPORT drumstick-file-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/drumstick
NAMESPACE Drumstick::
)
export(EXPORT drumstick-file-targets
NAMESPACE Drumstick::
FILE ${CMAKE_BINARY_DIR}/drumstick-file-targets.cmake
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(${CMAKE_BINARY_DIR}/drumstick-file-config-version.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_file( drumstick-file-config.cmake
${CMAKE_BINARY_DIR}/drumstick-file-config.cmake
@ONLY
)
install(FILES
${CMAKE_BINARY_DIR}/drumstick-file-config-version.cmake
${CMAKE_BINARY_DIR}/drumstick-file-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/drumstick
)
drumstick-2.9.0/library/file/qsmf.cpp 0000644 0001750 0001750 00000072003 14541630232 016572 0 ustar pedro pedro /*
Standard MIDI File component
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
Based on midifile.c by Tim Thompson, M.Czeiszperger and Greg Lee
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include
#include
#include
#include
#include
#include
#include
DISABLE_WARNING_PUSH
DISABLE_WARNING_DEPRECATED_DECLARATIONS
/**
* @file qsmf.cpp
* Implementation of a class managing Standard MIDI Files input/output
*/
namespace drumstick {
namespace File {
/**
* @addtogroup SMF
* @{
*
* QSmf provides a mechanism to parse and encode Standard MIDI Files, without
* the burden of a policy forcing to use some internal sequence representation.
*
* This class is not related or based on the ALSA library.
*
* @}
*/
class QSmf::QSmfPrivate {
public:
QSmfPrivate():
m_Interactive(false),
m_CurrTime(0),
m_RealTime(0),
m_DblRealTime(0),
m_DblOldRealtime(0),
m_Division(96),
m_CurrTempo(500000),
m_OldCurrTempo(500000),
m_OldRealTime(0),
m_OldCurrTime(0),
m_RevisedTime(0),
m_TempoChangeTime(0),
m_ToBeRead(0),
m_NumBytesWritten(0),
m_Tracks(0),
m_fileFormat(0),
m_LastStatus(0),
m_codec(nullptr),
m_IOStream(nullptr)
{ }
bool m_Interactive; /**< file and track headers are not required */
quint64 m_CurrTime; /**< current time in delta-time units */
quint64 m_RealTime; /**< current time in 1/16 centisecond-time units */
double m_DblRealTime; /**< as above, floating */
double m_DblOldRealtime;
int m_Division; /**< ticks per beat. Default = 96 */
quint64 m_CurrTempo; /**< microseconds per quarter note */
quint64 m_OldCurrTempo;
quint64 m_OldRealTime;
quint64 m_OldCurrTime;
quint64 m_RevisedTime;
quint64 m_TempoChangeTime;
quint64 m_ToBeRead;
quint64 m_NumBytesWritten;
int m_Tracks;
int m_fileFormat;
int m_LastStatus;
QTextCodec *m_codec;
QDataStream *m_IOStream;
QByteArray m_MsgBuff;
QList m_TempoList;
};
/**
* Constructor
* @param parent Optional parent object
*/
QSmf::QSmf(QObject * parent) :
QObject(parent),
d(new QSmfPrivate)
{ }
/**
* Destructor
*/
QSmf::~QSmf()
{
d->m_TempoList.clear();
}
/**
* Check if the SMF stream is positioned at the end.
* @return True if the SMF stream is at the end
*/
bool QSmf::endOfSmf()
{
return d->m_IOStream->atEnd();
}
/**
* Gets a single byte from the SMF stream
* @return A Single byte
*/
quint8 QSmf::getByte()
{
quint8 b = 0;
if (!endOfSmf())
{
*d->m_IOStream >> b;
d->m_ToBeRead--;
}
return b;
}
/**
* Puts a single byte to the SMF stream
* @param value A Single byte
*/
void QSmf::putByte(quint8 value)
{
*d->m_IOStream << value;
d->m_NumBytesWritten++;
}
/**
* Adds a tempo change to the internal tempo list
* @param tempo Tempo in microseconds per quarter
* @param time Location in ticks
*/
void QSmf::addTempo(quint64 tempo, quint64 time)
{
QSmfRecTempo tempoRec;
tempoRec.tempo = tempo;
tempoRec.time = time;
d->m_TempoList.append(tempoRec);
}
/**
* Reads a SMF header
*/
void QSmf::readHeader()
{
d->m_CurrTime = 0;
d->m_RealTime = 0;
d->m_Division = 96;
d->m_CurrTempo = 500000;
d->m_OldCurrTempo = 500000;
addTempo(d->m_CurrTempo, 0);
if (d->m_Interactive)
{
d->m_fileFormat= 0;
d->m_Tracks = 1;
d->m_Division = 96;
}
else
{
readExpected("MThd");
d->m_ToBeRead = read32bit();
d->m_fileFormat = read16bit();
d->m_Tracks = read16bit();
d->m_Division = read16bit();
}
Q_EMIT signalSMFHeader(d->m_fileFormat, d->m_Tracks, d->m_Division);
/* flush any extra stuff, in case the length of header is not */
while ((d->m_ToBeRead > 0) && !endOfSmf())
{
getByte();
}
if (d->m_ToBeRead > 0)
{
SMFError("Unexpected end of input");
}
}
/**
* Reads a track chunk
*/
void QSmf::readTrack()
{
/* This array is indexed by the high half of a status byte. It's
value is either the number of bytes needed (1 or 2) for a channel
message, or 0 (meaning it's not a channel message). */
static const quint8 chantype[16] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
quint64 lookfor;
quint8 c, c1, type;
bool sysexcontinue; // true if last message was an unfinished SysEx
bool running; // true when running status is used
quint8 status; // status value (e.g. 0x90==note-on)
int needed;
double delta_secs;
quint64 delta_ticks, save_time, save_tempo;
sysexcontinue = false;
status = 0;
if (d->m_Interactive)
{
d->m_ToBeRead = std::numeric_limits::max();
}
else
{
readExpected("MTrk");
d->m_ToBeRead = read32bit();
}
d->m_CurrTime = 0;
d->m_RealTime = 0;
d->m_DblRealTime = 0;
d->m_DblOldRealtime = 0;
d->m_OldCurrTime = 0;
d->m_OldRealTime = 0;
d->m_CurrTempo = findTempo();
Q_EMIT signalSMFTrackStart();
while (!endOfSmf() && (d->m_Interactive || d->m_ToBeRead > 0))
{
lookfor = 0;
if (d->m_Interactive)
{
d->m_CurrTime++;
}
else
{
delta_ticks = unsigned(readVarLen());
d->m_RevisedTime = d->m_CurrTime;
d->m_CurrTime += delta_ticks;
while (d->m_RevisedTime < d->m_CurrTime)
{
save_time = d->m_RevisedTime;
save_tempo = d->m_CurrTempo;
d->m_CurrTempo = findTempo();
if (d->m_CurrTempo != d->m_OldCurrTempo)
{
d->m_OldCurrTempo = d->m_CurrTempo;
d->m_OldRealTime = d->m_RealTime;
if (d->m_RevisedTime != d->m_TempoChangeTime)
{
d->m_DblOldRealtime = d->m_DblRealTime;
d->m_OldCurrTime = save_time;
}
delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
quint16(d->m_Division), save_tempo);
d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
d->m_RealTime = llround(d->m_DblRealTime);
if (d->m_RevisedTime == d->m_TempoChangeTime)
{
d->m_OldCurrTime = d->m_RevisedTime;
d->m_DblOldRealtime = d->m_DblRealTime;
}
}
else
{
delta_secs = ticksToSecs(d->m_RevisedTime - d->m_OldCurrTime,
quint16(d->m_Division), d->m_CurrTempo);
d->m_DblRealTime = d->m_DblOldRealtime + delta_secs * 1600.0;
d->m_RealTime = llround(d->m_DblRealTime);
}
}
}
c = getByte();
if (sysexcontinue && (c != end_of_sysex))
{
SMFError("didn't find expected continuation of a SysEx");
}
if (c < 0xf8)
{
if ((c & 0x80) == 0)
{
if (status == 0)
{
SMFError("unexpected running status");
}
running = true;
}
else
{
status = c;
running = false;
}
needed = chantype[status >> 4 & 0x0f];
if (needed != 0)
{
if (running)
{
c1 = c;
}
else
{
c1 = getByte();
}
if (needed > 1)
{
channelMessage(status, c1, getByte());
}
else
{
channelMessage(status, c1, 0);
}
continue;
}
}
switch (c)
{
case meta_event:
type = getByte();
lookfor = quint64(readVarLen());
lookfor = d->m_ToBeRead - lookfor;
msgInit();
while ((d->m_ToBeRead > lookfor) && !endOfSmf())
{
msgAdd(getByte());
}
metaEvent(type);
break;
case system_exclusive:
lookfor = quint64(readVarLen());
lookfor = d->m_ToBeRead - lookfor;
msgInit();
msgAdd(system_exclusive);
while ((d->m_ToBeRead > lookfor) && !endOfSmf())
{
c = getByte();
msgAdd(c);
}
if (c == end_of_sysex)
{
sysEx();
}
else
{
sysexcontinue = true;
}
break;
case end_of_sysex:
lookfor = readVarLen();
lookfor = d->m_ToBeRead - lookfor;
if (!sysexcontinue)
{
msgInit();
}
while ((d->m_ToBeRead > lookfor) && !endOfSmf())
{
c = getByte();
msgAdd(c);
}
if (sysexcontinue)
{
if (c == end_of_sysex)
{
sysEx();
sysexcontinue = false;
}
}
break;
default:
badByte(c, d->m_IOStream->device()->pos() - 1);
break;
}
if ((d->m_ToBeRead > lookfor) && endOfSmf()) {
SMFError("Unexpected end of input");
}
}
if (d->m_ToBeRead > 0) {
SMFError(QStringLiteral("Track ended before reading last %1 bytes").arg(d->m_ToBeRead));
}
Q_EMIT signalSMFTrackEnd();
}
/**
* Reads a SMF stream.
*/
void QSmf::SMFRead()
{
int i;
readHeader();
for ( i = d->m_Tracks; (i > 0) && !endOfSmf(); i--)
{
readTrack();
}
if (i > 0) {
SMFError(
QStringLiteral("%1 tracks out of a total of %2 are missing").arg(i).arg(d->m_Tracks));
}
}
/**
* Writes a SMF stream.
*
* Every MIDI file starts with a header.
* In format 1 files, the first track is a tempo map.
* The rest of the file is a series of tracks
*/
void QSmf::SMFWrite()
{
int i;
d->m_LastStatus = 0;
writeHeaderChunk(d->m_fileFormat, d->m_Tracks, d->m_Division);
d->m_LastStatus = 0;
if (d->m_fileFormat == 1)
{
Q_EMIT signalSMFWriteTempoTrack();
}
for (i = 0; i < d->m_Tracks; ++i)
{
writeTrackChunk(i);
}
}
/**
* Reads a SMF stream.
* @param stream Pointer to an existing and opened stream
*/
void QSmf::readFromStream(QDataStream *stream)
{
d->m_IOStream = stream;
SMFRead();
}
/**
* Reads a SMF stream from a disk file.
* @param fileName Name of an existing file.
*/
void QSmf::readFromFile(const QString& fileName)
{
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QDataStream ds(&file);
readFromStream(&ds);
file.close();
}
/**
* Writes a SMF stream
* @param stream Pointer to an existing and opened stream
*/
void QSmf::writeToStream(QDataStream *stream)
{
d->m_IOStream = stream;
SMFWrite();
}
/**
* Writes a SMF stream to a disk file
* @param fileName File name
*/
void QSmf::writeToFile(const QString& fileName)
{
QFile file(fileName);
file.open(QIODevice::WriteOnly);
QDataStream ds(&file);
writeToStream(&ds);
file.close();
}
/**
* Writes a SMF header chuck
* @param format SMF Format (0/1/2)
* @param ntracks Number of tracks
* @param division Resolution in ticks per quarter note
*/
void QSmf::writeHeaderChunk(int format, int ntracks, int division)
{
write32bit(MThd);
write32bit(6);
write16bit(quint16(format));
write16bit(quint16(ntracks));
write16bit(quint16(division));
}
/**
* Writes a track chuck
* @param track Number of the track
*/
void QSmf::writeTrackChunk(int track)
{
quint32 trkhdr;
quint32 trklength;
qint64 offset;
qint64 place_marker;
d->m_LastStatus = 0;
trkhdr = MTrk;
trklength = 0;
offset = d->m_IOStream->device()->pos();
write32bit(trkhdr);
write32bit(trklength);
d->m_NumBytesWritten = 0;
Q_EMIT signalSMFWriteTrack(track);
place_marker = d->m_IOStream->device()->pos();
d->m_IOStream->device()->seek(offset);
trklength = d->m_NumBytesWritten;
write32bit(trkhdr);
write32bit(trklength);
d->m_IOStream->device()->seek(place_marker);
}
/**
* Writes a variable length Meta Event
* @param deltaTime Time offset in ticks
* @param type Meta event type
* @param data Message data
*/
void QSmf::writeMetaEvent(long deltaTime, int type, const QByteArray& data)
{
writeVarLen(deltaTime);
d->m_LastStatus = meta_event;
putByte(d->m_LastStatus);
putByte(type);
writeVarLen(data.size());
foreach(char byte, data)
putByte(byte);
}
/**
* Writes a Text Meta Event
* @param deltaTime Time offset in ticks
* @param type Meta event type
* @param data Message text
*/
void QSmf::writeMetaEvent(long deltaTime, int type, const QString& data)
{
writeVarLen(deltaTime);
putByte(d->m_LastStatus = meta_event);
putByte(type);
QByteArray lcldata;
if (d->m_codec == nullptr)
lcldata = data.toLatin1();
else
lcldata = d->m_codec->fromUnicode(data);
writeVarLen(lcldata.length());
foreach(char byte, lcldata)
putByte(byte);
}
/**
* Writes a simple Meta event
* @param deltaTime Time offset in ticks
* @param type Meta event type
* @param data Meta event data
* @since 0.2.0
*/
void QSmf::writeMetaEvent(long deltaTime, int type, int data)
{
writeVarLen(deltaTime);
putByte(d->m_LastStatus = meta_event);
putByte(type);
putByte(1);
putByte(data);
}
/**
* Writes a simple Meta event
* @param deltaTime Time offset in ticks
* @param type Meta event type
*/
void QSmf::writeMetaEvent(long deltaTime, int type)
{
writeVarLen(deltaTime);
putByte(d->m_LastStatus = meta_event);
putByte(type);
putByte(0);
}
/**
* Writes a variable length MIDI message
* @param deltaTime Time offset in ticks
* @param type MIDI event type
* @param chan MIDI Channel
* @param data Message data
*/
void QSmf::writeMidiEvent(long deltaTime, int type, int chan,
const QByteArray& data)
{
unsigned int i, j, size;
quint8 c;
writeVarLen(quint64(deltaTime));
if ((type == system_exclusive) || (type == end_of_sysex))
{
c = type;
d->m_LastStatus = 0;
}
else
{
if (chan > 15)
{
SMFError("error: MIDI channel greater than 16");
}
c = type | chan;
}
if (d->m_LastStatus != c)
{
d->m_LastStatus = c;
putByte(c);
}
c = quint8(data[0]);
if (type == system_exclusive || type == end_of_sysex)
{
size = data.size();
if (type == c)
--size;
writeVarLen(size);
}
j = (c == type ? 1 : 0);
for (i = j; i < unsigned(data.size()); ++i)
{
putByte(quint8(data[i]));
}
}
/**
* Writes a MIDI message with a single parameter
* @param deltaTime Time offset in ticks
* @param type MIDI event type
* @param chan MIDI Channel
* @param b1 Message parameter
*/
void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1)
{
quint8 c;
writeVarLen(deltaTime);
if ((type == system_exclusive) || (type == end_of_sysex))
{
SMFError("error: Wrong method for a system exclusive event");
}
if (chan > 15)
{
SMFError("error: MIDI channel greater than 16");
}
c = type | chan;
if (d->m_LastStatus != c)
{
d->m_LastStatus = c;
putByte(c);
}
putByte(b1);
}
/**
* Writes a MIDI message with two parameters
* @param deltaTime Time offset in ticks
* @param type MIDI event type
* @param chan MIDI Channel
* @param b1 Message parameter 1
* @param b2 Message parameter 2
*/
void QSmf::writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2)
{
quint8 c;
writeVarLen(deltaTime);
if ((type == system_exclusive) || (type == end_of_sysex))
{
SMFError("error: Wrong method for a system exclusive event");
}
if (chan > 15)
{
SMFError("error: MIDI channel greater than 16");
}
c = type | chan;
if (d->m_LastStatus != c)
{
d->m_LastStatus = c;
putByte(c);
}
putByte(b1);
putByte(b2);
}
/**
* Writes a variable length MIDI message
* @param deltaTime Time offset in ticks
* @param type MIDI event type
* @param len Message length
* @param data Message data
*/
void QSmf::writeMidiEvent(long deltaTime, int type, long len, char* data)
{
unsigned int i, j, size;
quint8 c;
writeVarLen(quint64(deltaTime));
if ((type != system_exclusive) && (type != end_of_sysex))
{
SMFError("error: type should be system exclusive");
}
d->m_LastStatus = 0;
c = quint8(type);
putByte(c);
size = unsigned(len);
c = quint8(data[0]);
if (c == type)
--size;
writeVarLen(size);
j = (c == type ? 1 : 0);
for (i = j; i < unsigned(len); ++i)
{
putByte(quint8(data[i]));
}
}
/**
* Writes a MIDI Sequence number
* @param deltaTime Time offset in ticks
* @param seqnum Sequence number
*/
void QSmf::writeSequenceNumber(long deltaTime, int seqnum)
{
writeVarLen(deltaTime);
d->m_LastStatus = meta_event;
putByte(d->m_LastStatus);
putByte(sequence_number);
putByte(2);
putByte((seqnum >> 8) & 0xff);
putByte(seqnum & 0xff);
}
/**
* Writes a Tempo change message
* @param deltaTime Time offset in ticks
* @param tempo Tempo in microseconds per quarter note
*/
void QSmf::writeTempo(long deltaTime, long tempo)
{
writeVarLen(deltaTime);
putByte(d->m_LastStatus = meta_event);
putByte(set_tempo);
putByte(3);
putByte((tempo >> 16) & 0xff);
putByte((tempo >> 8) & 0xff);
putByte(tempo & 0xff);
}
/**
* Writes a Tempo change message
* @param deltaTime Time offset in ticks
* @param tempo Tempo expressed in quarter notes per minute
*/
void QSmf::writeBpmTempo(long deltaTime, int tempo)
{
long us_tempo = 60000000l / tempo;
writeTempo(deltaTime, us_tempo);
}
/**
* Writes a Time Signature message
* @param deltaTime Time offset in ticks
* @param num Numerator
* @param den Denominator (exponent for a power of two)
* @param cc Number of MIDI clocks in a metronome click
* @param bb Number of notated 32nd notes in 24 MIDI clocks
*/
void QSmf::writeTimeSignature(long deltaTime, int num, int den, int cc, int bb)
{
writeVarLen(deltaTime);
putByte(d->m_LastStatus = meta_event);
putByte(time_signature);
putByte(4);
putByte(num & 0xff);
putByte(den & 0xff);
putByte(cc & 0xff);
putByte(bb & 0xff);
}
/**
* Writes a key Signature message
* @param deltaTime Time offset in ticks
* @param tone Number of alterations (positive=sharps, negative=flats)
* @param mode Scale mode (0=major, 1=minor)
*/
void QSmf::writeKeySignature(long deltaTime, int tone, int mode)
{
writeVarLen(quint64(deltaTime));
putByte(d->m_LastStatus = meta_event);
putByte(key_signature);
putByte(2);
putByte(quint8(tone));
putByte(mode & 0x01);
}
/**
* Writes multi-length bytes
* @param value Integer value
*/
void QSmf::writeVarLen(quint64 value)
{
quint64 buffer;
buffer = value & 0x7f;
while ((value >>= 7) > 0)
{
buffer <<= 8;
buffer |= 0x80;
buffer += (value & 0x7f);
}
while (true)
{
putByte(buffer & 0xff);
if (buffer & 0x80)
buffer >>= 8;
else
break;
}
}
/* These routines are used to make sure that the byte order of
the various data types remains constant between machines. */
void QSmf::write32bit(quint32 data)
{
putByte((data >> 24) & 0xff);
putByte((data >> 16) & 0xff);
putByte((data >> 8) & 0xff);
putByte(data & 0xff);
}
void QSmf::write16bit(quint16 data)
{
putByte((data >> 8) & 0xff);
putByte(data & 0xff);
}
quint16 QSmf::to16bit(quint8 c1, quint8 c2)
{
quint16 value;
value = quint16(c1 << 8);
value += c2;
return value;
}
quint32 QSmf::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
{
quint32 value;
value = unsigned(c1 << 24);
value += unsigned(c2 << 16);
value += unsigned(c3 << 8);
value += c4;
return value;
}
quint16 QSmf::read16bit()
{
quint8 c1, c2;
c1 = getByte();
c2 = getByte();
return to16bit(c1, c2);
}
quint32 QSmf::read32bit()
{
quint8 c1, c2, c3, c4;
c1 = getByte();
c2 = getByte();
c3 = getByte();
c4 = getByte();
return to32bit(c1, c2, c3, c4);
}
long QSmf::readVarLen()
{
quint64 value;
quint8 c;
c = getByte();
value = c;
if ((c & 0x80) != 0)
{
value &= 0x7f;
do
{
c = getByte();
value = (value << 7) + (c & 0x7f);
} while ((c & 0x80) != 0);
}
return long(value);
}
void QSmf::readExpected(const QString& s)
{
int j;
quint8 b;
for (j = 0; j < s.length(); ++j)
{
b = getByte();
if (QChar(b) != s[j])
{
SMFError(QString("Invalid (%1) SMF format at %2").arg(b, 0, 16).arg(d->m_IOStream->device()->pos()));
break;
}
}
}
quint64 QSmf::findTempo()
{
quint64 result, old_tempo, new_tempo;
QSmfRecTempo rec = d->m_TempoList.last();
old_tempo = d->m_CurrTempo;
new_tempo = d->m_CurrTempo;
QList::Iterator it;
for( it = d->m_TempoList.begin(); it != d->m_TempoList.end(); ++it )
{
rec = (*it);
if (rec.time <= d->m_CurrTime)
{
old_tempo = rec.tempo;
}
new_tempo = rec.tempo;
if (rec.time > d->m_RevisedTime)
{
break;
}
}
if ((rec.time <= d->m_RevisedTime) || (rec.time > d->m_CurrTime))
{
d->m_RevisedTime = d->m_CurrTime;
result = old_tempo;
}
else
{
d->m_RevisedTime = rec.time;
d->m_TempoChangeTime = d->m_RevisedTime;
result = new_tempo;
}
return result;
}
/* This routine converts delta times in ticks into seconds. The
else statement is needed because the formula is different for tracks
based on notes and tracks based on SMPTE times. */
double QSmf::ticksToSecs(quint64 ticks, quint16 division, quint64 tempo)
{
double result;
double smpte_format;
double smpte_resolution;
if (division > 0)
{
result = double(ticks * tempo)/(division * 1000000.0);
}
else
{
smpte_format = upperByte(division);
smpte_resolution = lowerByte(division);
result = double(ticks)/(smpte_format * smpte_resolution
* 1000000.0);
}
return result;
}
void QSmf::SMFError(const QString& s)
{
Q_EMIT signalSMFError(s);
}
void QSmf::channelMessage(quint8 status, quint8 c1, quint8 c2)
{
quint8 chan;
int k;
chan = status & midi_channel_mask;
if (c1 > 127)
{
SMFError(QString("ChannelMessage with bad c1 = %1").arg(c1));
//c1 &= 127;
}
if (c2 > 127)
{
SMFError(QString("ChannelMessage with bad c2 = %1").arg(c2));
//c2 &= 127;
}
switch (status & midi_command_mask)
{
case note_off:
Q_EMIT signalSMFNoteOff(chan, c1, c2);
break;
case note_on:
Q_EMIT signalSMFNoteOn(chan, c1, c2);
break;
case poly_aftertouch:
Q_EMIT signalSMFKeyPress(chan, c1, c2);
break;
case control_change:
Q_EMIT signalSMFCtlChange(chan, c1, c2);
break;
case program_chng:
Q_EMIT signalSMFProgram(chan, c1);
break;
case channel_aftertouch:
Q_EMIT signalSMFChanPress(chan, c1);
break;
case pitch_wheel:
k = c1 + (c2 << 7) - 8192;
Q_EMIT signalSMFPitchBend(chan, k);
break;
default:
SMFError(QString("Invalid MIDI status %1. Unhandled event").arg(status));
break;
}
}
void QSmf::metaEvent(quint8 b)
{
QSmfRecTempo rec;
QByteArray m(d->m_MsgBuff);
switch (b)
{
case sequence_number:
Q_EMIT signalSMFSequenceNum(to16bit(m[0], m[1]));
break;
case text_event:
case copyright_notice:
case sequence_name:
case instrument_name:
case lyric:
case marker:
case cue_point: {
QString s;
if (d->m_codec == nullptr) {
Q_EMIT signalSMFText2(b, m);
} else {
s = d->m_codec->toUnicode(m);
Q_EMIT signalSMFText(b, s);
}
}
break;
case forced_channel:
Q_EMIT signalSMFforcedChannel(m[0]);
break;
case forced_port:
Q_EMIT signalSMFforcedPort(m[0]);
break;
case end_of_track:
Q_EMIT signalSMFendOfTrack();
break;
case set_tempo:
d->m_CurrTempo = to32bit(0, m[0], m[1], m[2]);
Q_EMIT signalSMFTempo(d->m_CurrTempo);
rec = d->m_TempoList.last();
if (rec.tempo == d->m_CurrTempo)
{
return;
}
if (rec.time > d->m_CurrTime)
{
return;
}
addTempo(d->m_CurrTempo, d->m_CurrTime);
break;
case smpte_offset:
Q_EMIT signalSMFSmpte(m[0], m[1], m[2], m[3], m[4]);
break;
case time_signature:
Q_EMIT signalSMFTimeSig(m[0], m[1], m[2], m[3]);
break;
case key_signature:
Q_EMIT signalSMFKeySig(m[0], m[1]);
break;
case sequencer_specific:
Q_EMIT signalSMFSeqSpecific(m);
break;
default:
Q_EMIT signalSMFMetaUnregistered(b, m);
break;
}
Q_EMIT signalSMFMetaMisc(b, m);
}
void QSmf::sysEx()
{
QByteArray varr(d->m_MsgBuff);
Q_EMIT signalSMFSysex(varr);
}
void QSmf::badByte(quint8 b, int p)
{
SMFError(QString("Unexpected byte (%1) at %2").arg(b, 2, 16).arg(p));
}
quint8 QSmf::lowerByte(quint16 x)
{
return (x & 0xff);
}
quint8 QSmf::upperByte(quint16 x)
{
return ((x >> 8) & 0xff);
}
void QSmf::msgInit()
{
d->m_MsgBuff.truncate(0);
}
void QSmf::msgAdd(quint8 b)
{
int s = d->m_MsgBuff.size();
d->m_MsgBuff.resize(s + 1);
d->m_MsgBuff[s] = b;
}
/* public properties (accessors) */
/**
* Gets the current time in ticks
* @return Time in ticks
*/
long QSmf::getCurrentTime()
{
return d->m_CurrTime;
}
/**
* Gets the current tempo
* @return Tempo in us per quarter
*/
long QSmf::getCurrentTempo()
{
return d->m_CurrTempo;
}
/**
* Gets the real time in seconds
* @return Time in seconds
*/
long QSmf::getRealTime()
{
return d->m_RealTime;
}
/**
* Gets the resolution
* @return Resolution in ticks per quarter note
*/
int QSmf::getDivision()
{
return d->m_Division;
}
/**
* Sets the resolution
* @param division Resolution in ticks per quarter note
*/
void QSmf::setDivision(int division)
{
d->m_Division = division;
}
/**
* Gets the number of tracks
* @return Number of tracks
*/
int QSmf::getTracks()
{
return d->m_Tracks;
}
/**
* Sets the number of tracks
* @param tracks Number of tracks
*/
void QSmf::setTracks(int tracks)
{
d->m_Tracks = tracks;
}
/**
* Gets the SMF file format
* @return File format (0, 1, or 2)
*/
int QSmf::getFileFormat()
{
return d->m_fileFormat;
}
/**
* Sets the SMF file format
* @param fileFormat File format (0, 1, or 2)
*/
void QSmf::setFileFormat(int fileFormat)
{
d->m_fileFormat = fileFormat;
}
/**
* Gets the position in the SMF stream
* @return Position offset in the stream
*/
long QSmf::getFilePos()
{
return long(d->m_IOStream->device()->pos());
}
/**
* Gets the text codec used for text meta-events I/O
* @return QTextCodec pointer
* @since 0.2.0
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
*/
QTextCodec* QSmf::getTextCodec()
{
return d->m_codec;
}
/**
* Sets the text codec for text meta-events.
* The engine doesn't take ownership of the codec instance.
*
* @param codec QTextCodec pointer
* @since 0.2.0
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
*/
void QSmf::setTextCodec(QTextCodec *codec)
{
d->m_codec = codec;
}
/**
* @brief drumstickLibraryVersion provides the Drumstick version as an edited QString
* @return Drumstick library version
*/
QString drumstickLibraryVersion()
{
return QStringLiteral(QT_STRINGIFY(VERSION));
}
} // namespace File
} // namespace drumstick
DISABLE_WARNING_POP
drumstick-2.9.0/library/file/qwrk.cpp 0000644 0001750 0001750 00000104423 14541630232 016612 0 ustar pedro pedro /*
WRK File component
Copyright (C) 2010-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
DISABLE_WARNING_PUSH
DISABLE_WARNING_DEPRECATED_DECLARATIONS
/**
* @file qwrk.cpp
* Implementation of a class managing Cakewalk WRK Files input
*/
namespace drumstick { namespace File {
/**
* @addtogroup WRK
* @{
*
* QWrk provides a mechanism to parse Cakewalk WRK Files, without
* the burden of a policy forcing to use some internal sequence representation.
*
* This class is not related or based on the ALSA library.
*
* @}
*/
class QWrk::QWrkPrivate {
public:
QWrkPrivate():
m_Now(0),
m_From(0),
m_Thru(11930),
m_KeySig(0),
m_Clock(0),
m_AutoSave(0),
m_PlayDelay(0),
m_ZeroCtrls(false),
m_SendSPP(true),
m_SendCont(true),
m_PatchSearch(false),
m_AutoStop(false),
m_StopTime(4294967295U),
m_AutoRewind(false),
m_RewindTime(0),
m_MetroPlay(false),
m_MetroRecord(true),
m_MetroAccent(false),
m_CountIn(1),
m_ThruOn(true),
m_AutoRestart(false),
m_CurTempoOfs(1),
m_TempoOfs1(32),
m_TempoOfs2(64),
m_TempoOfs3(128),
m_PunchEnabled(false),
m_PunchInTime(0),
m_PunchOutTime(0),
m_EndAllTime(0),
m_division(120),
m_codec(nullptr),
m_IOStream(nullptr)
{ }
quint32 m_Now; ///< Now marker time
quint32 m_From; ///< From marker time
quint32 m_Thru; ///< Thru marker time
quint8 m_KeySig; ///< Key signature (0=C, 1=C#, ... 11=B)
quint8 m_Clock; ///< Clock Source (0=Int, 1=MIDI, 2=FSK, 3=SMPTE)
quint8 m_AutoSave; ///< Auto save (0=disabled, 1..256=minutes)
quint8 m_PlayDelay; ///< Play Delay
bool m_ZeroCtrls; ///< Zero continuous controllers?
bool m_SendSPP; ///< Send Song Position Pointer?
bool m_SendCont; ///< Send MIDI Continue?
bool m_PatchSearch; ///< Patch/controller search-back?
bool m_AutoStop; ///< Auto-stop?
quint32 m_StopTime; ///< Auto-stop time
bool m_AutoRewind; ///< Auto-rewind?
quint32 m_RewindTime; ///< Auto-rewind time
bool m_MetroPlay; ///< Metronome on during playback?
bool m_MetroRecord; ///< Metronome on during recording?
bool m_MetroAccent; ///< Metronome accents primary beats?
quint8 m_CountIn; ///< Measures of count-in (0=no count-in)
bool m_ThruOn; ///< MIDI Thru enabled? (only used if no THRU rec)
bool m_AutoRestart; ///< Auto-restart?
quint8 m_CurTempoOfs; ///< Which of the 3 tempo offsets is used: 0..2
quint8 m_TempoOfs1; ///< Fixed-point ratio value of offset 1
quint8 m_TempoOfs2; ///< Fixed-point ratio value of offset 2
quint8 m_TempoOfs3; ///< Fixed-point ratio value of offset 3
bool m_PunchEnabled; ///< Auto-Punch enabled?
quint32 m_PunchInTime; ///< Punch-in time
quint32 m_PunchOutTime; ///< Punch-out time
quint32 m_EndAllTime; ///< Time of latest event (incl. all tracks)
int m_division;
QTextCodec *m_codec;
QDataStream *m_IOStream;
QByteArray m_lastChunkData;
QList m_tempos;
qint64 m_lastChunkPos;
qint64 internalFilePos();
};
/**
* Constructor
* @param parent Object owner
*/
QWrk::QWrk(QObject * parent) :
QObject(parent),
d(new QWrkPrivate)
{ }
/**
* Destructor
*/
QWrk::~QWrk()
{ }
/**
* Gets the text codec used for text meta-events I/O.
*
* @return QTextCodec pointer
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
*/
QTextCodec* QWrk::getTextCodec()
{
return d->m_codec;
}
/**
* Sets the text codec for text meta-events.
* The engine doesn't take ownership of the codec instance.
*
* @param codec QTextCodec pointer
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
*/
void QWrk::setTextCodec(QTextCodec *codec)
{
d->m_codec = codec;
}
/**
* Gets the last chunk raw data (undecoded)
*
* @return last chunk raw data
*/
QByteArray QWrk::getLastChunkRawData() const
{
return d->m_lastChunkData;
}
/**
* Read the chunk raw data (undecoded)
*/
void QWrk::readRawData(int size)
{
if (size > 0) {
d->m_lastChunkData = d->m_IOStream->device()->read(size);
} else {
d->m_lastChunkData.clear();
//qDebug() << Q_FUNC_INFO << "Size error:" << size;
}
}
/**
* Now marker time
* @return Now marker time
*/
int QWrk::getNow() const
{
return d->m_Now;
}
/**
* From marker time
* @return From marker time
*/
int QWrk::getFrom() const
{
return d->m_From;
}
/**
* Thru marker time
* @return Thru marker time
*/
int QWrk::getThru() const
{
return d->m_Thru;
}
/**
* Key signature (0=C, 1=C#, ... 11=B)
* @return Key signature
*/
int QWrk::getKeySig() const
{
return d->m_KeySig;
}
/**
* Clock Source (0=Int, 1=MIDI, 2=FSK, 3=SMPTE)
* @return Clock Source
*/
int QWrk::getClock() const
{
return d->m_Clock;
}
/**
* Auto save (0=disabled, 1..256=minutes)
* @return Auto save
*/
int QWrk::getAutoSave() const
{
return d->m_AutoSave;
}
/**
* Play Delay
* @return Play Delay
*/
int QWrk::getPlayDelay() const
{
return d->m_PlayDelay;
}
/**
* Zero continuous controllers?
* @return Zero continuous controllers
*/
bool QWrk::getZeroCtrls() const
{
return d->m_ZeroCtrls;
}
/**
* Send Song Position Pointer?
* @return Send Song Position Pointer
*/
bool QWrk::getSendSPP() const
{
return d->m_SendSPP;
}
/**
* Send MIDI Continue?
* @return Send MIDI Continue
*/
bool QWrk::getSendCont() const
{
return d->m_SendCont;
}
/**
* Patch/controller search-back?
* @return Patch/controller search-back
*/
bool QWrk::getPatchSearch() const
{
return d->m_PatchSearch;
}
/**
* Auto-stop?
* @return Auto-stop
*/
bool QWrk::getAutoStop() const
{
return d->m_AutoStop;
}
/**
* Auto-stop time
* @return Auto-stop time
*/
unsigned int QWrk::getStopTime() const
{
return d->m_StopTime;
}
/**
* Auto-rewind?
* @return Auto-rewind
*/
bool QWrk::getAutoRewind() const
{
return d->m_AutoRewind;
}
/**
* Auto-rewind time
* @return Auto-rewind time
*/
int QWrk::getRewindTime() const
{
return d->m_RewindTime;
}
/**
* Metronome on during playback?
* @return Metronome on during playback
*/
bool QWrk::getMetroPlay() const
{
return d->m_MetroPlay;
}
/**
* Metronome on during recording?
* @return Metronome on during recording
*/
bool QWrk::getMetroRecord() const
{
return d->m_MetroRecord;
}
/**
* Metronome accents primary beats?
* @return Metronome accents primary beats
*/
bool QWrk::getMetroAccent() const
{
return d->m_MetroAccent;
}
/**
* Measures of count-in (0=no count-in)
* @return Measures of count-in
*/
int QWrk::getCountIn() const
{
return d->m_CountIn;
}
/**
* MIDI Thru enabled? (only used if no THRU rec)
* @return MIDI Thru enabled
*/
bool QWrk::getThruOn() const
{
return d->m_ThruOn;
}
/**
* Auto-restart?
* @return Auto-restart
*/
bool QWrk::getAutoRestart() const
{
return d->m_AutoRestart;
}
/**
* Which of the 3 tempo offsets is used: 0..2
* @return tempo offset index
*/
int QWrk::getCurTempoOfs() const
{
return d->m_CurTempoOfs;
}
/**
* Fixed-point ratio value of tempo offset 1
*
* NOTE: The offset ratios are expressed as a numerator in the expression
* n/64. To get a ratio from this number, divide the number by 64. To get
* this number from a ratio, multiply the ratio by 64.
* Examples:
* 32 ==> 32/64 = 0.5
* 63 ==> 63/64 = 0.9
* 64 ==> 64/64 = 1.0
* 128 ==> 128/64 = 2.0
*
* @return tempo offset 1
*/
int QWrk::getTempoOfs1() const
{
return d->m_TempoOfs1;
}
/**
* Fixed-point ratio value of tempo offset 2
*
* NOTE: The offset ratios are expressed as a numerator in the expression
* n/64. To get a ratio from this number, divide the number by 64. To get
* this number from a ratio, multiply the ratio by 64.
* Examples:
* 32 ==> 32/64 = 0.5
* 63 ==> 63/64 = 0.9
* 64 ==> 64/64 = 1.0
* 128 ==> 128/64 = 2.0
*
* @return tempo offset 2
*/
int QWrk::getTempoOfs2() const
{
return d->m_TempoOfs2;
}
/**
* Fixed-point ratio value of tempo offset 3
*
* NOTE: The offset ratios are expressed as a numerator in the expression
* n/64. To get a ratio from this number, divide the number by 64. To get
* this number from a ratio, multiply the ratio by 64.
* Examples:
* 32 ==> 32/64 = 0.5
* 63 ==> 63/64 = 0.9
* 64 ==> 64/64 = 1.0
* 128 ==> 128/64 = 2.0
*
* @return tempo offset 3
*/
int QWrk::getTempoOfs3() const
{
return d->m_TempoOfs3;
}
/**
* Auto-Punch enabled?
* @return Auto-Punch enabled
*/
bool QWrk::getPunchEnabled() const
{
return d->m_PunchEnabled;
}
/**
* Punch-in time
* @return punch-in time
*/
int QWrk::getPunchInTime() const
{
return d->m_PunchInTime;
}
/**
* Punch-out time
* @return Punch-out time
*/
int QWrk::getPunchOutTime() const
{
return d->m_PunchOutTime;
}
/**
* Time of latest event (incl. all tracks)
* @return Time of latest event
*/
int QWrk::getEndAllTime() const
{
return d->m_EndAllTime;
}
/**
* Gets a single byte from the stream
* @return A Single byte
*/
quint8 QWrk::readByte()
{
quint8 b = 0xff;
if (!d->m_IOStream->atEnd())
*d->m_IOStream >> b;
return b;
}
/**
* Converts two bytes into a single 16-bit value
* @param c1 first byte
* @param c2 second byte
* @return 16-bit value
*/
quint16 QWrk::to16bit(quint8 c1, quint8 c2)
{
quint16 value = (c1 << 8);
value += c2;
return value;
}
/**
* Converts four bytes into a single 32-bit value
* @param c1 1st byte
* @param c2 2nd byte
* @param c3 3rd byte
* @param c4 4th byte
* @return 32-bit value
*/
quint32 QWrk::to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4)
{
quint32 value = (c1 << 24);
value += (c2 << 16);
value += (c3 << 8);
value += c4;
return value;
}
/**
* Reads a 16-bit value
* @return 16-bit value
*/
quint16 QWrk::read16bit()
{
quint8 c1, c2;
c1 = readByte();
c2 = readByte();
return to16bit(c2, c1);
}
/**
* Reads a 24-bit value
* @return 32-bit value
*/
quint32 QWrk::read24bit()
{
quint8 c1, c2, c3;
c1 = readByte();
c2 = readByte();
c3 = readByte();
return to32bit(0, c3, c2, c1);
}
/**
* Reads a 32-bit value
* @return 32-bit value
*/
quint32 QWrk::read32bit()
{
quint8 c1, c2, c3, c4;
c1 = readByte();
c2 = readByte();
c3 = readByte();
c4 = readByte();
return to32bit(c4, c3, c2, c1);
}
/**
* Reads a string assuming local encoding if getTextCodec() is null
* @return a string
*/
QString QWrk::readString(int len)
{
QString s;
if ( len > 0 ) {
QByteArray data = readByteArray(len);
if (d->m_codec == nullptr) {
s = QString::fromLatin1(data);
} else {
s = d->m_codec->toUnicode(data);
}
}
return s;
}
/**
* Reads a string as a QByteArray (without decoding)
* @return a string
*/
QByteArray QWrk::readByteArray(int len)
{
QByteArray data;
if ( len > 0 ) {
quint8 c = 0xff;
for ( int i = 0; i < len && c != 0 && !atEnd(); ++i ) {
c = readByte();
if ( c != 0)
data += c;
}
}
return data;
}
/**
* Reads a variable length string (C-style)
* (assuming local encoding if getTextCodec() is null)
* @return a string
*/
QString QWrk::readVarString()
{
QString s;
QByteArray data = readVarByteArray();
if (d->m_codec == nullptr) {
s = QString::fromLatin1(data);
} else {
s = d->m_codec->toUnicode(data);
}
return s;
}
/**
* Reads a variable length string (C-style) as a QByteArray (without decoding)
* @return a string
*/
QByteArray QWrk::readVarByteArray()
{
QByteArray data;
quint8 b;
do {
b = readByte();
if (b != 0)
data += b;
} while (b != 0 && !atEnd());
return data;
}
void QWrk::processMarkers()
{
int num = read32bit();
for (int i = 0; (i < num) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i) {
int smpte = readByte();
readGap(1);
long time = read24bit();
readGap(5);
int len = readByte();
if (d->m_codec == nullptr) {
QByteArray data = readByteArray(len);
Q_EMIT signalWRKMarker2(time, smpte, data);
} else {
QString name = readString(len);
Q_EMIT signalWRKMarker(time, smpte, name);
}
}
}
/**
* Current position in the data stream
* @return current position
*/
long QWrk::getFilePos()
{
return d->internalFilePos();
}
/**
* Seeks to a new position in the data stream
* @param pos new position
*/
void QWrk::seek(qint64 pos)
{
if (!d->m_IOStream->device()->seek(pos)) {
//qDebug() << Q_FUNC_INFO << "Error, pos:" << pos;
}
}
/**
* Checks if the data stream pointer has reached the end position
* @return true if the read pointer is at end
*/
bool QWrk::atEnd()
{
return d->m_IOStream->atEnd();
}
/**
* Jumps the given size in the data stream
* @param size the gap size
*/
void QWrk::readGap(int size)
{
if ( size > 0)
seek( d->internalFilePos() + size );
}
/**
* Reads a stream.
* @param stream Pointer to an existing and opened stream
*/
void QWrk::readFromStream(QDataStream *stream)
{
d->m_IOStream = stream;
wrkRead();
}
/**
* Reads a stream from a disk file.
* @param fileName Name of an existing file.
*/
void QWrk::readFromFile(const QString& fileName)
{
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QDataStream ds(&file);
readFromStream(&ds);
file.close();
}
void QWrk::processTrackChunk()
{
int namelen;
QString name[2];
QByteArray data[2];
int trackno;
int channel;
int pitch;
int velocity;
int port;
bool selected;
bool muted;
bool loop;
trackno = read16bit();
for(int i=0; i<2; ++i) {
namelen = readByte();
if (d->m_codec == nullptr) {
data[i] = readByteArray(namelen);
} else {
name[i] = readString(namelen);
}
}
channel = readByte() & 0x0f;
pitch = readByte();
velocity = readByte();
port = readByte();
quint8 flags = readByte();
selected = ((flags & 1) != 0);
muted = ((flags & 2) != 0);
loop = ((flags & 4) != 0);
if (d->m_codec == nullptr) {
Q_EMIT signalWRKTrack2( data[0], data[1],
trackno, channel, pitch,
velocity, port, selected,
muted, loop );
} else {
Q_EMIT signalWRKTrack( name[0], name[1],
trackno, channel, pitch,
velocity, port, selected,
muted, loop );
}
}
void QWrk::processVarsChunk()
{
d->m_Now = read32bit();
d->m_From = read32bit();
d->m_Thru = read32bit();
d->m_KeySig = readByte();
d->m_Clock = readByte();
d->m_AutoSave = readByte();
d->m_PlayDelay = readByte();
readGap(1);
d->m_ZeroCtrls = (readByte() != 0);
d->m_SendSPP = (readByte() != 0);
d->m_SendCont = (readByte() != 0);
d->m_PatchSearch = (readByte() != 0);
d->m_AutoStop = (readByte() != 0);
d->m_StopTime = read32bit();
d->m_AutoRewind = (readByte() != 0);
d->m_RewindTime = read32bit();
d->m_MetroPlay = (readByte() != 0);
d->m_MetroRecord = (readByte() != 0);
d->m_MetroAccent = (readByte() != 0);
d->m_CountIn = readByte();
readGap(2);
d->m_ThruOn = (readByte() != 0);
readGap(19);
d->m_AutoRestart = (readByte() != 0);
d->m_CurTempoOfs = readByte();
d->m_TempoOfs1 = readByte();
d->m_TempoOfs2 = readByte();
d->m_TempoOfs3 = readByte();
readGap(2);
d->m_PunchEnabled = (readByte() != 0);
d->m_PunchInTime = read32bit();
d->m_PunchOutTime = read32bit();
d->m_EndAllTime = read32bit();
Q_EMIT signalWRKGlobalVars();
}
void QWrk::processTimebaseChunk()
{
quint16 timebase = read16bit();
d->m_division = timebase;
Q_EMIT signalWRKTimeBase(timebase);
}
void QWrk::processNoteArray(int track, int events)
{
quint32 time = 0;
quint8 status = 0, data1 = 0, data2 = 0, i = 0;
quint16 dur = 0;
int value = 0, type = 0, channel = 0, len = 0;
QString text;
QByteArray data;
for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
time = read24bit();
status = readByte();
dur = 0;
if (status >= 0x90) {
type = status & 0xf0;
channel = status & 0x0f;
data1 = readByte();
if (type == 0x90 || type == 0xA0 || type == 0xB0 || type == 0xE0)
data2 = readByte();
if (type == 0x90)
dur = read16bit();
switch (type) {
case 0x90:
Q_EMIT signalWRKNote(track, time, channel, data1, data2, dur);
break;
case 0xA0:
Q_EMIT signalWRKKeyPress(track, time, channel, data1, data2);
break;
case 0xB0:
Q_EMIT signalWRKCtlChange(track, time, channel, data1, data2);
break;
case 0xC0:
Q_EMIT signalWRKProgram(track, time, channel, data1);
break;
case 0xD0:
Q_EMIT signalWRKChanPress(track, time, channel, data1);
break;
case 0xE0:
value = (data2 << 7) + data1 - 8192;
Q_EMIT signalWRKPitchBend(track, time, channel, value);
break;
case 0xF0:
Q_EMIT signalWRKSysexEvent(track, time, data1);
break;
}
} else if (status == 5) {
int code = read16bit();
len = read32bit();
if (d->m_codec == nullptr) {
data = readByteArray(len);
Q_EMIT signalWRKExpression2(track, time, code, data);
} else {
text = readString(len);
Q_EMIT signalWRKExpression(track, time, code, text);
}
} else if (status == 6) {
int code = read16bit();
dur = read16bit();
readGap(4);
Q_EMIT signalWRKHairpin(track, time, code, dur);
} else if (status == 7) {
len = read32bit();
text = readString(len);
data.clear();
for(int j=0; j<13; ++j) {
int byte = readByte();
data += byte;
}
Q_EMIT signalWRKChord(track, time, text, data);
} else if (status == 8) {
len = read16bit();
data.clear();
for(int j=0; jm_codec == nullptr) {
data = readByteArray(len);
Q_EMIT signalWRKText2(track, time, status, data);
} else {
text = readString(len);
Q_EMIT signalWRKText(track, time, status, text);
}
}
}
if ((i < events) && atEnd()) {
Q_EMIT signalWRKError("Corrupted file");
}
Q_EMIT signalWRKStreamEnd(time + dur);
}
void QWrk::processStreamChunk()
{
long time = 0;
int dur = 0, value = 0, type = 0, channel = 0, i = 0;
quint8 status = 0, data1 = 0, data2 = 0;
quint16 track = read16bit();
int events = read16bit();
for ( i = 0; (i < events) && (d->internalFilePos() < d->m_lastChunkPos) && !atEnd(); ++i ) {
time = read24bit();
status = readByte();
data1 = readByte();
data2 = readByte();
dur = read16bit();
type = status & 0xf0;
channel = status & 0x0f;
switch (type) {
case 0x90:
Q_EMIT signalWRKNote(track, time, channel, data1, data2, dur);
break;
case 0xA0:
Q_EMIT signalWRKKeyPress(track, time, channel, data1, data2);
break;
case 0xB0:
Q_EMIT signalWRKCtlChange(track, time, channel, data1, data2);
break;
case 0xC0:
Q_EMIT signalWRKProgram(track, time, channel, data1);
break;
case 0xD0:
Q_EMIT signalWRKChanPress(track, time, channel, data1);
break;
case 0xE0:
value = (data2 << 7) + data1 - 8192;
Q_EMIT signalWRKPitchBend(track, time, channel, value);
break;
case 0xF0:
Q_EMIT signalWRKSysexEvent(track, time, data1);
break;
}
}
if ((i < events) && atEnd()) {
Q_EMIT signalWRKError("Corrupted file");
}
Q_EMIT signalWRKStreamEnd(time + dur);
}
void QWrk::processMeterChunk()
{
int count = read16bit();
for (int i = 0; i < count; ++i) {
readGap(4);
int measure = read16bit();
int num = readByte();
int den = pow(2.0, readByte());
readGap(4);
Q_EMIT signalWRKTimeSig(measure, num, den);
}
}
void QWrk::processMeterKeyChunk()
{
int count = read16bit();
for (int i = 0; i < count; ++i) {
int measure = read16bit();
int num = readByte();
int den = pow(2.0, readByte());
qint8 alt = readByte();
Q_EMIT signalWRKTimeSig(measure, num, den);
Q_EMIT signalWRKKeySig(measure, alt);
}
}
double QWrk::getRealTime(long ticks) const
{
double division = 1.0 * d->m_division;
RecTempo last;
last.time = 0;
last.tempo = 100.0;
last.seconds = 0.0;
if (!d->m_tempos.isEmpty()) {
foreach(const RecTempo& rec, d->m_tempos) {
if (rec.time >= ticks)
break;
last = rec;
}
}
return last.seconds + (((ticks - last.time) / division) * (60.0 / last.tempo));
}
void QWrk::processTempoChunk(int factor)
{
double division = 1.0 * d->m_division;
int count = read16bit();
RecTempo last, next;
for (int i = 0; i < count; ++i) {
long time = read32bit();
readGap(4);
long tempo = read16bit() * factor;
readGap(8);
next.time = time;
next.tempo = tempo / 100.0;
next.seconds = 0.0;
last.time = 0;
last.tempo = next.tempo;
last.seconds = 0.0;
if (! d->m_tempos.isEmpty()) {
foreach(const RecTempo& rec, d->m_tempos) {
if (rec.time >= time)
break;
last = rec;
}
next.seconds = last.seconds +
(((time - last.time) / division) * (60.0 / last.tempo));
}
d->m_tempos.append(next);
Q_EMIT signalWRKTempo(time, tempo);
}
}
void QWrk::processSysexChunk()
{
int j;
QString name;
QByteArray data;
int bank = readByte();
int length = read16bit();
bool autosend = (readByte() != 0);
int namelen = readByte();
name = readString(namelen);
for(j=0; j> 4;
bool autosend = ( (b & 0x0f) != 0);
int namelen = readByte();
name = readString(namelen);
for(j=0; j127
qint8 channel = readByte(); // -1, 0->15
qint8 keyPlus = readByte(); // 0->127
qint8 velPlus = readByte(); // 0->127
qint8 localPort = readByte();
qint8 mode = readByte();
Q_EMIT signalWRKThru(mode, port, channel, keyPlus, velPlus, localPort);
}
void QWrk::processTrackOffset()
{
quint16 track = read16bit();
qint16 offset = read16bit();
Q_EMIT signalWRKTrackOffset(track, offset);
}
void QWrk::processTrackReps()
{
quint16 track = read16bit();
quint16 reps = read16bit();
Q_EMIT signalWRKTrackReps(track, reps);
}
void QWrk::processTrackPatch()
{
quint16 track = read16bit();
qint8 patch = readByte();
Q_EMIT signalWRKTrackPatch(track, patch);
}
void QWrk::processTimeFormat()
{
quint16 fmt = read16bit();
quint16 ofs = read16bit();
Q_EMIT signalWRKTimeFormat(fmt, ofs);
}
void QWrk::processComments()
{
int len = read16bit();
if (d->m_codec == nullptr) {
QByteArray data = readByteArray(len);
Q_EMIT signalWRKComments2(data);
} else {
QString text = readString(len);
Q_EMIT signalWRKComments(text);
}
}
void QWrk::processVariableRecord(int max)
{
int datalen = max - 32;
QByteArray data;
QString name = readVarString();
readGap(31 - name.length());
for ( int i = 0; i < datalen; ++i ) {
data += readByte();
}
while (data.endsWith('\0')) {
data.chop(1);
}
Q_EMIT signalWRKVariableRecord(name, data);
}
void QWrk::processUnknown(int id)
{
Q_EMIT signalWRKUnknownChunk(id, d->m_lastChunkData);
}
void QWrk::processNewTrack()
{
QByteArray data;
QString name;
qint16 bank = -1;
qint16 patch = -1;
//qint16 vol = -1;
//qint16 pan = -1;
qint8 key = -1;
qint8 vel = 0;
quint8 port = 0;
qint8 channel = 0;
bool selected = false;
bool muted = false;
bool loop = false;
quint16 track = read16bit();
quint8 len = readByte();
if (d->m_codec == nullptr) {
data = readByteArray(len);
} else {
name = readString(len);
}
bank = read16bit();
patch = read16bit();
/*vol =*/ read16bit();
/*pan =*/ read16bit();
key = readByte();
vel = readByte();
readGap(7);
port = readByte();
channel = readByte();
muted = (readByte() != 0);
if (d->m_codec == nullptr) {
Q_EMIT signalWRKNewTrack2(data, track, channel, key, vel, port, selected, muted, loop);
} else {
Q_EMIT signalWRKNewTrack(name, track, channel, key, vel, port, selected, muted, loop);
}
if (bank > -1)
Q_EMIT signalWRKTrackBank(track, bank);
if (patch > -1) {
if (channel > -1)
Q_EMIT signalWRKProgram(track, 0, channel, patch);
else
Q_EMIT signalWRKTrackPatch(track, patch);
}
}
void QWrk::processSoftVer()
{
int len = readByte();
QString vers = readString(len);
Q_EMIT signalWRKSoftVer(vers);
}
void QWrk::processTrackName()
{
int track = read16bit();
int len = readByte();
if (d->m_codec == nullptr) {
QByteArray data = readByteArray(len);
Q_EMIT signalWRKTrackName2(track, data);
} else {
QString name = readString(len);
Q_EMIT signalWRKTrackName(track, name);
}
}
void QWrk::processStringTable()
{
if (d->m_codec == nullptr) {
QList table;
int rows = read16bit();
for (int i = 0; i < rows; ++i) {
int len = readByte();
QByteArray name = readByteArray(len);
/*int idx =*/ readByte();
table.insert(i, name);
}
Q_EMIT signalWRKStringTable2(table);
} else {
QStringList table;
int rows = read16bit();
for (int i = 0; i < rows; ++i) {
int len = readByte();
QString name = readString(len);
/*int idx =*/ readByte();
table.insert(i, name);
}
Q_EMIT signalWRKStringTable(table);
}
}
void QWrk::processLyricsStream()
{
quint16 track = read16bit();
int events = read32bit();
processNoteArray(track, events);
}
void QWrk::processTrackVol()
{
quint16 track = read16bit();
int vol = read16bit();
Q_EMIT signalWRKTrackVol(track, vol);
}
void QWrk::processNewTrackOffset()
{
quint16 track = read16bit();
int offset = read32bit();
Q_EMIT signalWRKTrackOffset(track, offset);
}
void QWrk::processTrackBank()
{
quint16 track = read16bit();
int bank = read16bit();
Q_EMIT signalWRKTrackBank(track, bank);
}
void QWrk::processSegmentChunk()
{
QString name;
QByteArray data;
int track = read16bit();
int offset = read32bit();
readGap(8);
int len = readByte();
if (d->m_codec == nullptr) {
data = readByteArray(len);
} else {
name = readString(len);
}
readGap(20);
if (d->m_codec == nullptr) {
Q_EMIT signalWRKSegment2(track, offset, data);
} else {
Q_EMIT signalWRKSegment(track, offset, name);
}
int events = read32bit();
processNoteArray(track, events);
}
void QWrk::processNewStream()
{
QString name;
QByteArray data;
int track = read16bit();
int len = readByte();
if (d->m_codec == nullptr) {
data = readByteArray(len);
Q_EMIT signalWRKSegment2(track, 0, data);
} else {
name = readString(len);
Q_EMIT signalWRKSegment(track, 0, name);
}
int events = read32bit();
processNoteArray(track, events);
}
void QWrk::processEndChunk()
{
Q_EMIT signalWRKEnd();
}
int QWrk::readChunk()
{
qint64 start_pos = d->internalFilePos();
int ck = readByte();
if (ck != END_CHUNK) {
quint32 ck_len = read32bit();
if (ck_len > d->m_IOStream->device()->bytesAvailable()) {
Q_EMIT signalWRKError("Corrupted file");
seek(start_pos);
return END_CHUNK;
}
start_pos = d->internalFilePos();
d->m_lastChunkPos = start_pos + ck_len;
readRawData(ck_len);
seek(start_pos);
switch (ck) {
case TRACK_CHUNK:
processTrackChunk();
break;
case VARS_CHUNK:
processVarsChunk();
break;
case TIMEBASE_CHUNK:
processTimebaseChunk();
break;
case STREAM_CHUNK:
processStreamChunk();
break;
case METER_CHUNK:
processMeterChunk();
break;
case TEMPO_CHUNK:
processTempoChunk(100);
break;
case NTEMPO_CHUNK:
processTempoChunk();
break;
case SYSEX_CHUNK:
processSysexChunk();
break;
case THRU_CHUNK:
processThruChunk();
break;
case TRKOFFS_CHUNK:
processTrackOffset();
break;
case TRKREPS_CHUNK:
processTrackReps();
break;
case TRKPATCH_CHUNK:
processTrackPatch();
break;
case TIMEFMT_CHUNK:
processTimeFormat();
break;
case COMMENTS_CHUNK:
processComments();
break;
case VARIABLE_CHUNK:
processVariableRecord(ck_len);
break;
case NTRACK_CHUNK:
processNewTrack();
break;
case SOFTVER_CHUNK:
processSoftVer();
break;
case TRKNAME_CHUNK:
processTrackName();
break;
case STRTAB_CHUNK:
processStringTable();
break;
case LYRICS_CHUNK:
processLyricsStream();
break;
case TRKVOL_CHUNK:
processTrackVol();
break;
case NTRKOFS_CHUNK:
processNewTrackOffset();
break;
case TRKBANK_CHUNK:
processTrackBank();
break;
case METERKEY_CHUNK:
processMeterKeyChunk();
break;
case SYSEX2_CHUNK:
processSysex2Chunk();
break;
case NSYSEX_CHUNK:
processNewSysexChunk();
break;
case SGMNT_CHUNK:
processSegmentChunk();
break;
case NSTREAM_CHUNK:
processNewStream();
break;
case MARKERS_CHUNK:
processMarkers();
break;
default:
processUnknown(ck);
}
if (d->internalFilePos() != d->m_lastChunkPos) {
//qDebug() << Q_FUNC_INFO << "Current pos:" << d->internalFilePos() << "should be:" << d->m_lastChunkPos;
seek(d->m_lastChunkPos);
}
}
return ck;
}
void QWrk::wrkRead()
{
QByteArray hdr(HEADER.length(), ' ');
d->m_tempos.clear();
d->m_IOStream->device()->read(hdr.data(), HEADER.length());
if (hdr == HEADER) {
int vma, vme;
int ck_id;
readGap(1);
vme = readByte();
vma = readByte();
Q_EMIT signalWRKHeader(vma, vme);
do {
ck_id = readChunk();
} while ((ck_id != END_CHUNK) && !atEnd());
if (!atEnd()) {
//qDebug() << Q_FUNC_INFO << "extra junk past the end at" << d->internalFilePos();
readRawData(d->m_IOStream->device()->bytesAvailable());
processUnknown(ck_id);
}
processEndChunk();
} else
Q_EMIT signalWRKError("Invalid file format");
}
qint64 QWrk::QWrkPrivate::internalFilePos()
{
return m_IOStream->device()->pos();
}
const QByteArray QWrk::HEADER = QByteArrayLiteral("CAKEWALK");
} // namespace File
} // namespace drumstick
DISABLE_WARNING_POP
drumstick-2.9.0/library/file/rmid.cpp 0000644 0001750 0001750 00000016706 14541630232 016567 0 ustar pedro pedro /*
Standard RIFF MIDI Component
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#include
#include
#include
#include
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
#define right Qt::right
#define left Qt::left
#define endl Qt::endl
#define hex Qt::hex
#define dec Qt::dec
#endif
/**
* @file rmid.cpp
* Implementation of a class managing RIFF MIDI Files input
*/
namespace drumstick { namespace File {
/**
* @addtogroup RMID
* @{
*
* Rmidi provides a mechanism to parse RIFF RMID Files, without the burden of a policy forcing to use some internal sequence representation.
*
* RIFF RMID is a wrapper format for MIDI data, as first specified by Microsoft, and later extended by MIDI.org (an arm of the MIDI Manufacturers Association) to permit the bundling of both MIDI files and Downloadable Sounds (DLS) files. According to Multimedia Programming Interface and Data Specifications 1.0, August 1991.: The 'RMID' format consists of a standard MIDI file enclosed in a RIFF chunk. Enclosing the MIDI file in a 'RIFF' chunk allows the file to be consistently identified; for example, an 'INFO' list can be included in the file.
*
* This implementation does not yet support embedded DLS data. This format is deprecated in favor of Extensible Music Files (XMF).
*
* This class is not related or based on the ALSA library. To parse the SMF portion of the format, the QSmf class should be used.
*
* @see https://www.loc.gov/preservation/digital/formats/fdd/fdd000120.shtml
* @see http://web.archive.org/web/20110610135604/http://www.midi.org/about-midi/rp29spec(rmid).pdf
* @}
*/
const quint32 CKID_RIFF = 0x46464952;
const quint32 CKID_LIST = 0x5453494c;
const quint32 CKID_INFO = 0x4f464e49;
const quint32 CKID_RMID = 0x44494d52;
const quint32 CKID_data = 0x61746164;
const quint32 CKID_DISP = 0x50534944;
const quint32 CKID_DLS = 0x20534C44;
/**
* Constructor
* @param parent Object owner
*/
Rmidi::Rmidi(QObject * parent):
QObject(parent)
{ }
/**
* Destructor
*/
Rmidi::~Rmidi()
{ }
/**
* Reads a stream from a disk file.
* @param fileName Name of an existing file.
*/
void Rmidi::readFromFile(QString fileName)
{
//qDebug() << Q_FUNC_INFO << fileName;
QFile file(m_fileName = fileName);
file.open(QIODevice::ReadOnly);
QDataStream ds(&file);
readFromStream(&ds);
file.close();
}
/**
* Reads a stream.
* @param ds Pointer to an existing and opened input stream
*/
void Rmidi::readFromStream(QDataStream* ds)
{
//qDebug() << Q_FUNC_INFO;
if (ds != nullptr) {
m_stream = ds;
m_stream->setByteOrder(QDataStream::LittleEndian);
read();
}
}
QString Rmidi::toString(quint32 ckid)
{
QByteArray data(reinterpret_cast(&ckid), sizeof(quint32));
return QString::fromLatin1(data);
}
QByteArray Rmidi::readByteArray(int size)
{
//qDebug() << Q_FUNC_INFO << size;
char *buffer = new char[size];
m_stream->readRawData(buffer, size);
QByteArray ba(buffer);
delete[] buffer;
return ba;
}
void Rmidi::skip(quint32 cktype, int size)
{
Q_UNUSED(cktype)
//qDebug() << Q_FUNC_INFO << toString(cktype) << size;
m_stream->skipRawData(size);
}
quint32 Rmidi::readExpectedChunk(quint32 cktype)
{
quint32 chunkType, len = 0;
*m_stream >> chunkType;
if (chunkType == cktype) {
*m_stream >> len;
if (len % 2) len++; // alignment to even size
/*qDebug() << Q_FUNC_INFO
<< "Expected:" << toString(chunkType)
<< "(" << hex << chunkType << ")"
<< "length:" << dec << len;*/
} /*else {
qDebug() << Q_FUNC_INFO
<< "Expected:" << toString(cktype)
<< "(" << hex << cktype << ")"
<< "got instead:" << toString(chunkType)
<< "(" << hex << chunkType << ")";
}*/
return len;
}
quint32 Rmidi::readChunk(quint32& chunkType)
{
quint32 len = 0;
*m_stream >> chunkType;
*m_stream >> len;
if (len % 2) len++; // alignment to even size
/*qDebug() << Q_FUNC_INFO
<< "chunkType:" << toString(chunkType)
<< "(" << hex << chunkType << ")"
<< "length:" << dec << len;*/
return len;
}
quint32 Rmidi::readChunkID()
{
quint32 chunkID;
*m_stream >> chunkID;
/*qDebug() << Q_FUNC_INFO
<< "chunkID:" << toString(chunkID)
<< "(" << hex << chunkID << ")";*/
return chunkID;
}
void Rmidi::processINFO(int size)
{
//qDebug() << Q_FUNC_INFO << size;
quint32 chunkID = 0;
quint32 length = 0;
while ((size > 0) && !m_stream->atEnd()) {
length = readChunk(chunkID);
size -= 8;
size -= length;
QString cktype = toString(chunkID);
QByteArray data = readByteArray(length);
Q_EMIT signalRiffInfo(cktype, data);
}
}
void Rmidi::processList(int size)
{
//qDebug() << Q_FUNC_INFO;
quint32 chunkID = 0;
if (m_stream->atEnd()) return;
chunkID = readChunkID();
size -= 4;
switch (chunkID) {
case CKID_INFO:
processINFO(size);
break;
default:
skip(chunkID, size);
}
}
void Rmidi::processRMID(int size)
{
//qDebug() << Q_FUNC_INFO << size;
quint32 chunkID = 0;
int length;
while ((size > 0) && !m_stream->atEnd()) {
length = readChunk(chunkID);
size -= 8;
switch (chunkID) {
case CKID_data:
processData("RMID", length);
break;
case CKID_LIST:
processList(length);
break;
case CKID_DISP:
skip(chunkID, length);
break;
case CKID_RIFF:
processRIFF(length);
break;
default:
skip(chunkID, length);
}
size -= length;
}
}
void Rmidi::processRIFF(int size)
{
quint32 chunkID = readChunkID();
quint32 length = size - 4;
switch(chunkID) {
case CKID_RMID:
//qDebug() << "RMID format";
processRMID(length);
break;
case CKID_DLS:
//qDebug() << "DLS format";
if (m_stream->device() != nullptr && m_stream->device()->pos() >= 12) {
m_stream->device()->seek(m_stream->device()->pos() - 12);
processData("DLS", length + 12);
} else {
skip(chunkID, length);
}
break;
default:
qWarning() << "Unsupported format";
skip(chunkID, length);
}
}
void Rmidi::processData(const QString& dataType, int size)
{
//qDebug() << Q_FUNC_INFO << size;
QByteArray memdata(size, '\0');
m_stream->readRawData(memdata.data(), size);
Q_EMIT signalRiffData(dataType, memdata);
}
void Rmidi::read()
{
//qDebug() << Q_FUNC_INFO;
quint32 length = readExpectedChunk(CKID_RIFF);
if (length > 0) {
processRIFF(length);
}
}
}} // namespace drumstick::File
drumstick-2.9.0/library/include/ 0000755 0001750 0001750 00000000000 14541630232 015622 5 ustar pedro pedro drumstick-2.9.0/library/include/drumstick.h 0000644 0001750 0001750 00000003222 14541630232 017777 0 ustar pedro pedro /*
Drumstick MIDI C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_H
#define DRUMSTICK_H
#include
/**
* @file drumstick.h
* The main header that a program can include to use all drumstick features.
*/
#if defined(Q_OS_LINUX)
// ALSA library interface
#include
#include
#include
#include
#include
#include
#include
#include
#endif
// File formats
#include
#include
#include
// RealTime interfaces
#include
#include
#include
// Widgets
#include
#include
#include
#include
#endif /*DRUMSTICK_H*/
drumstick-2.9.0/library/include/drumstick/ 0000755 0001750 0001750 00000000000 14541630232 017627 5 ustar pedro pedro drumstick-2.9.0/library/include/drumstick/alsaevent.h 0000644 0001750 0001750 00000060325 14541630232 021770 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_ALSAEVENT_H
#define DRUMSTICK_ALSAEVENT_H
extern "C" {
#include
}
#include
#include
#include "macros.h"
namespace drumstick { namespace ALSA {
/**
* @file alsaevent.h
* Classes managing ALSA Sequencer events.
*
* @addtogroup ALSAEvent ALSA Sequencer Events
* @{
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
/**
* 8-bit unsigned number to be used as a MIDI message parameter
*/
typedef quint8 MidiByte;
/**
* Constant SequencerEventType is the QEvent::type() of any SequencerEvent
* object to be used to check the argument in QObject::customEvent().
*/
const QEvent::Type SequencerEventType = QEvent::Type(QEvent::User + 4154); // :-)
/**
* Base class for the event's hierarchy
*
* All event classes share this base class. It provides several common
* properties and methods.
*/
class DRUMSTICK_ALSA_EXPORT SequencerEvent : public QEvent
{
public:
SequencerEvent();
SequencerEvent(const SequencerEvent& other);
explicit SequencerEvent(const snd_seq_event_t* event);
SequencerEvent& operator=(const SequencerEvent& other);
void setSequencerType(const snd_seq_event_type_t eventType);
/**
* Gets the sequencer event type.
* @return The sequencer event type.
* @see setSequencerType()
*/
snd_seq_event_type_t getSequencerType() const { return m_event.type; }
void setDestination(const unsigned char client, const unsigned char port);
void setSource(const unsigned char port);
/**
* Gets the source client id.
* @return The source client id.
* @see setSource()
*/
unsigned char getSourceClient() const { return m_event.source.client; }
/**
* Gets the source port id.
* @return The source port id.
* @see setSource()
*/
unsigned char getSourcePort() const { return m_event.source.port; }
/**
* Gets the tick time of the event.
* @return The tick time.
* @see scheduleTick()
*/
snd_seq_tick_time_t getTick() const { return m_event.time.tick; }
/**
* Gets the seconds of the event's real time.
* @return The seconds of the time.
* @see scheduleReal(), getRealTimeNanos()
*/
unsigned int getRealTimeSecs() const { return m_event.time.time.tv_sec; }
/**
* Gets the nanoseconds of the event's real time.
* @return The nanoseconds of the time.
* @see scheduleReal(), getRealTimeSecs()
*/
unsigned int getRealTimeNanos() const { return m_event.time.time.tv_nsec; }
void setSubscribers();
void setBroadcast();
void setDirect();
void scheduleTick(const int queue, const int tick, const bool relative);
void scheduleReal(const int queue, const ulong secs, const ulong nanos, const bool relative);
void setPriority(const bool high);
/**
* Gets the tag of the event
* @return The event's tag
* @see setTag()
*/
unsigned char getTag() const { return m_event.tag; }
void setTag(const unsigned char aTag);
unsigned int getRaw32(const unsigned int n) const;
void setRaw32(const unsigned int n, const unsigned int value);
unsigned char getRaw8(const unsigned int n) const;
void setRaw8(const unsigned int n, const unsigned char value);
/**
* Gets the handle of the event
* @return The event's handle
*/
snd_seq_event_t* getHandle() { return &m_event; }
int getEncodedLength();
static bool isSubscription(const SequencerEvent* event);
static bool isPort(const SequencerEvent* event);
static bool isClient(const SequencerEvent* event);
static bool isConnectionChange(const SequencerEvent* event);
static bool isChannel(const SequencerEvent* event);
virtual SequencerEvent* clone() const;
protected:
Q_DECL_DEPRECATED void free();
/**
* ALSA sequencer event record.
* @see https://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__event.html
*/
snd_seq_event_t m_event;
};
/**
* Base class for the events having a Channel property
*/
class DRUMSTICK_ALSA_EXPORT ChannelEvent : public SequencerEvent
{
public:
/** Default constructor */
ChannelEvent() : SequencerEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit ChannelEvent(const snd_seq_event_t* event) : SequencerEvent(event) {}
/**
* Sets the channel of the event
* @param c A channel, between 0 and 15.
* @see getChannel()
*/
void setChannel(const MidiByte c) { m_event.data.note.channel = (c & 0xf); }
/**
* Gets the event's channel
* @return The event's channel
* @see setChannel()
*/
int getChannel() const { return m_event.data.note.channel; }
virtual ChannelEvent* clone() const override;
};
/**
* Base class for the events having Key and Velocity properties.
*/
class DRUMSTICK_ALSA_EXPORT KeyEvent : public ChannelEvent
{
public:
/** Default constructor */
KeyEvent() : ChannelEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit KeyEvent(const snd_seq_event_t* event) : ChannelEvent(event) {}
/**
* Gets the MIDI note of this event.
* @return The event's MIDI note.
* @see setKey()
*/
int getKey() const { return m_event.data.note.note; }
/**
* Sets the MIDI note of this event.
* @param b A MIDI note, between 0 and 127.
* @see getKey()
*/
void setKey(const MidiByte b) { m_event.data.note.note = b; }
/**
* Gets the note velocity of this event.
* @return The event's note velocity.
* @see setVelocity()
*/
int getVelocity() const { return m_event.data.note.velocity; }
/**
* Sets the note velocity of this event.
* @param b A velocity value, between 0 and 127.
* @see getVelocity()
*/
void setVelocity(const MidiByte b) { m_event.data.note.velocity = b; }
virtual KeyEvent* clone() const override;
};
/**
* Class representing a note event with duration
*
* Note events are converted into two MIDI events, a note-on and a note-off
* over the wire.
*/
class DRUMSTICK_ALSA_EXPORT NoteEvent : public KeyEvent
{
public:
/** Default constructor */
NoteEvent() : KeyEvent() { m_event.type = SND_SEQ_EVENT_NOTE; }
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit NoteEvent(const snd_seq_event_t* event) : KeyEvent(event) {}
/**
* Constructor
*/
NoteEvent(const int ch, const int key, const int vel, const int dur);
/**
* Gets the note's duration
* @return The duration of the event
* @see setDuration()
*/
ulong getDuration() const { return m_event.data.note.duration; }
/**
* Sets the note's duration
* @param d The duration of the event
* @see getDuration()
*/
void setDuration(const ulong d) { m_event.data.note.duration = d; }
virtual NoteEvent* clone() const override;
};
/**
* Event representing a note-on MIDI event
*/
class DRUMSTICK_ALSA_EXPORT NoteOnEvent : public KeyEvent
{
public:
/** Default constructor */
NoteOnEvent() : KeyEvent() { m_event.type = SND_SEQ_EVENT_NOTEON; }
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit NoteOnEvent(const snd_seq_event_t* event) : KeyEvent(event) {}
/**
* Constructor
*/
NoteOnEvent(const int ch, const int key, const int vel);
virtual NoteOnEvent* clone() const override;
};
/**
* Event representing a note-off MIDI event
*/
class DRUMSTICK_ALSA_EXPORT NoteOffEvent : public KeyEvent
{
public:
/** Default constructor */
NoteOffEvent() : KeyEvent() { m_event.type = SND_SEQ_EVENT_NOTEOFF; }
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit NoteOffEvent(const snd_seq_event_t* event) : KeyEvent(event) {}
/**
* Constructor
*/
NoteOffEvent(const int ch, const int key, const int vel);
virtual NoteOffEvent* clone() const override;
};
/**
* Event representing a MIDI key pressure, or polyphonic after-touch event
*/
class DRUMSTICK_ALSA_EXPORT KeyPressEvent : public KeyEvent
{
public:
/** Default constructor */
KeyPressEvent() : KeyEvent() { m_event.type = SND_SEQ_EVENT_KEYPRESS; }
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit KeyPressEvent(const snd_seq_event_t* event) : KeyEvent(event) {}
/**
* Constructor
*/
KeyPressEvent(const int ch, const int key, const int vel);
virtual KeyPressEvent* clone() const override;
};
/**
* Event representing a MIDI control change event
*/
class DRUMSTICK_ALSA_EXPORT ControllerEvent : public ChannelEvent
{
public:
/** Default constructor */
ControllerEvent() : ChannelEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit ControllerEvent(const snd_seq_event_t* event) : ChannelEvent(event) {}
/**
* Constructor
*/
ControllerEvent(const int ch, const int cc, const int val);
/**
* Gets the controller event's parameter.
* @return The controller event's parameter.
* @see setParam()
*/
uint getParam() const { return m_event.data.control.param; }
/**
* Sets the controller event's parameter.
* @param p The controller event's parameter.
* @see getParam()
*/
void setParam( const uint p ) { m_event.data.control.param = p; }
/**
* Gets the controller event's value.
* @return The controller event's value.
* @see setValue()
*/
int getValue() const { return m_event.data.control.value; }
/**
* Sets the controller event's value.
* @param v The controller event's value.
* @see getValue()
*/
void setValue( const int v ) { m_event.data.control.value = v; }
virtual ControllerEvent* clone() const override;
};
/**
* Event representing a MIDI program change event
*/
class DRUMSTICK_ALSA_EXPORT ProgramChangeEvent : public ChannelEvent
{
public:
/** Default constructor */
ProgramChangeEvent() : ChannelEvent() { m_event.type = SND_SEQ_EVENT_PGMCHANGE; }
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit ProgramChangeEvent(const snd_seq_event_t* event) : ChannelEvent(event) {}
/**
* Constructor
*/
ProgramChangeEvent(const int ch, const int val);
/**
* Gets the MIDI program number
* @return the MIDI program number
*/
int getValue() const { return m_event.data.control.value; }
/**
* Sets the MIDI program number
* @param v the MIDI program number
*/
void setValue( const int v ) { m_event.data.control.value = v; }
virtual ProgramChangeEvent* clone() const override;
};
/**
* Event representing a MIDI bender, or pitch wheel event
*/
class DRUMSTICK_ALSA_EXPORT PitchBendEvent : public ChannelEvent
{
public:
/** Default constructor */
PitchBendEvent() : ChannelEvent() { m_event.type = SND_SEQ_EVENT_PITCHBEND; }
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit PitchBendEvent(const snd_seq_event_t* event) : ChannelEvent(event) {}
/**
* Constructor
*/
PitchBendEvent(const int ch, const int val);
/**
* Gets the MIDI pitch bend value, zero centered from -8192 to 8191
* @return the MIDI pitch bend value
*/
int getValue() const { return m_event.data.control.value; }
/**
* Sets the MIDI pitch bend value, zero centered from -8192 to 8191
* @param v the MIDI pitch bend value
*/
void setValue( const int v ) { m_event.data.control.value = v; }
virtual PitchBendEvent* clone() const override;
};
/**
* Event representing a MIDI channel pressure or after-touch event
*/
class DRUMSTICK_ALSA_EXPORT ChanPressEvent : public ChannelEvent
{
public:
/** Default constructor */
ChanPressEvent() : ChannelEvent() { m_event.type = SND_SEQ_EVENT_CHANPRESS; }
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit ChanPressEvent( const snd_seq_event_t* event ) : ChannelEvent(event) {}
/**
* Constructor
*/
ChanPressEvent( const int ch, const int val );
/**
* Gets the channel aftertouch value
* @return the channel aftertouch value
*/
int getValue() const { return m_event.data.control.value; }
/**
* Sets the channel aftertouch value
* @param v the channel aftertouch value
*/
void setValue( const int v ) { m_event.data.control.value = v; }
virtual ChanPressEvent* clone() const override;
};
/**
* Base class for variable length events
*/
class DRUMSTICK_ALSA_EXPORT VariableEvent : public SequencerEvent
{
public:
VariableEvent();
explicit VariableEvent(const snd_seq_event_t* event);
explicit VariableEvent(const QByteArray& data);
VariableEvent(const VariableEvent& other);
VariableEvent(const unsigned int datalen, char* dataptr);
VariableEvent& operator=(const VariableEvent& other);
/**
* Gets the data length
* @return the data length
*/
unsigned int getLength() const { return m_event.data.ext.len; }
/**
* Gets the data pointer
* @return the data pointer
*/
const char* getData() const { return static_cast(m_event.data.ext.ptr); }
virtual VariableEvent* clone() const override;
protected:
QByteArray m_data;
};
/**
* Event representing a MIDI system exclusive event
*/
class DRUMSTICK_ALSA_EXPORT SysExEvent : public VariableEvent
{
public:
SysExEvent();
explicit SysExEvent(const snd_seq_event_t* event);
explicit SysExEvent(const QByteArray& data);
SysExEvent(const SysExEvent& other);
SysExEvent(const unsigned int datalen, char* dataptr);
SysExEvent &operator=(const SysExEvent &other);
virtual SysExEvent* clone() const override;
};
/**
* Event representing a SMF text event
*
* This event type is not intended to be transmitted over the wire to an
* external device, but it is useful for sequencer programs or MIDI applications
*/
class DRUMSTICK_ALSA_EXPORT TextEvent : public VariableEvent
{
public:
TextEvent();
explicit TextEvent(const snd_seq_event_t* event);
explicit TextEvent(const QString& text, const int textType = 1);
TextEvent(const TextEvent& other);
TextEvent(const unsigned int datalen, char* dataptr);
TextEvent &operator=(const TextEvent &other);
QString getText() const;
int getTextType() const;
virtual TextEvent* clone() const override;
protected:
int m_textType;
};
/**
* Generic event
*/
class DRUMSTICK_ALSA_EXPORT SystemEvent : public SequencerEvent
{
public:
/** Default constructor */
SystemEvent() : SequencerEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit SystemEvent(const snd_seq_event_t* event) : SequencerEvent(event) {}
explicit SystemEvent(const snd_seq_event_type_t type);
virtual SystemEvent* clone() const override;
};
/**
* ALSA Event representing a queue control command
*
* This event is used to schedule changes to the ALSA queues
*/
class DRUMSTICK_ALSA_EXPORT QueueControlEvent : public SequencerEvent
{
public:
/** Default constructor */
QueueControlEvent() : SequencerEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit QueueControlEvent(const snd_seq_event_t* event) : SequencerEvent(event) {}
QueueControlEvent(const snd_seq_event_type_t type, const int queue, const int value);
/**
* Gets the queue number
* @return the queue number
*/
int getQueue() const { return m_event.data.queue.queue; }
/**
* Sets the queue number
* @param q the queue number
*/
void setQueue(const uchar q) { m_event.data.queue.queue = q; }
/**
* Gets the event's value
* @return the event's value
*/
int getValue() const { return m_event.data.queue.param.value; }
/**
* Sets the event's value
* @param val the event's value
*/
void setValue(const int val) { m_event.data.queue.param.value = val; }
/**
* Gets the queue position
* @return the queue position
*/
uint getPosition() const { return m_event.data.queue.param.position; }
/**
* Sets the queue position
* @param pos the queue position
*/
void setPosition(const uint pos) { m_event.data.queue.param.position = pos; }
/**
* Gets the musical time in ticks
* @return the musical time in ticks
*/
snd_seq_tick_time_t getTickTime() const { return m_event.data.queue.param.time.tick; }
/**
* Sets the musical time in ticks
* @param t the musical time in ticks
*/
void setTickTime(const snd_seq_tick_time_t t) { m_event.data.queue.param.time.tick = t; }
/**
* Gets the skew base
* @return the skew base
*/
uint getSkewBase() const { return m_event.data.queue.param.skew.base; }
/**
* Sets the skew base, should be 65536
* @param base the skew base, should be 65536
*/
void setSkewBase(const uint base) { m_event.data.queue.param.skew.base = base; }
/**
* Gets the skew value
* @return the skew value
*/
uint getSkewValue() const { return m_event.data.queue.param.skew.value; }
/**
* Sets the skew value
* @param val the skew value
*/
void setSkewValue(const uint val) {m_event.data.queue.param.skew.value = val; }
virtual QueueControlEvent* clone() const override;
};
/**
* Generic event having a value property
*/
class DRUMSTICK_ALSA_EXPORT ValueEvent : public SequencerEvent
{
public:
/** Default constructor */
ValueEvent() : SequencerEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit ValueEvent(const snd_seq_event_t* event) : SequencerEvent(event) {}
ValueEvent(const snd_seq_event_type_t type, const int val);
/**
* Gets the event's value
* @return the event's value
*/
int getValue() const { return m_event.data.control.value; }
/**
* Sets the event's value
* @param v the event's value
*/
void setValue( const int v ) { m_event.data.control.value = v; }
virtual ValueEvent* clone() const override;
};
/**
* ALSA Event representing a tempo change for an ALSA queue
*/
class DRUMSTICK_ALSA_EXPORT TempoEvent : public QueueControlEvent
{
public:
/** Default constructor */
TempoEvent() : QueueControlEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit TempoEvent(const snd_seq_event_t* event) : QueueControlEvent(event) {}
TempoEvent(const int queue, const int tempo);
virtual TempoEvent* clone() const override;
};
/**
* ALSA Event representing a subscription between two ALSA clients and ports
*/
class DRUMSTICK_ALSA_EXPORT SubscriptionEvent : public SequencerEvent
{
public:
/** Default constructor */
SubscriptionEvent() : SequencerEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit SubscriptionEvent(const snd_seq_event_t* event) : SequencerEvent(event) {}
/**
* Returns true if the event was a subscribed port
* @return whether the event was a subscribed port
*/
bool subscribed() const { return (m_event.type == SND_SEQ_EVENT_PORT_SUBSCRIBED); }
/**
* Returns true if the event was an unsubscribed port
* @return whether the event was an unsubscribed port
*/
bool unsubscribed() const { return (m_event.type == SND_SEQ_EVENT_PORT_UNSUBSCRIBED); }
/**
* Gets the sender client number
* @return the sender client number
*/
int getSenderClient() const { return m_event.data.connect.sender.client; }
/**
* Gets the sender port number
* @return the sender port number
*/
int getSenderPort() const { return m_event.data.connect.sender.port; }
/**
* Gets the destination client number
* @return the destination client number
*/
int getDestClient() const { return m_event.data.connect.dest.client; }
/**
* Gets the destination port number
* @return the destination port number
*/
int getDestPort() const { return m_event.data.connect.dest.port; }
virtual SubscriptionEvent* clone() const override;
};
/**
* ALSA Event representing a change on some ALSA sequencer client on the system
*/
class DRUMSTICK_ALSA_EXPORT ClientEvent : public SequencerEvent
{
public:
/** Default constructor */
ClientEvent() : SequencerEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit ClientEvent(const snd_seq_event_t* event) : SequencerEvent(event) {}
/**
* Gets the client number
* @return the client number
*/
int getClient() const { return m_event.data.addr.client; }
virtual ClientEvent* clone() const override;
};
/**
* ALSA Event representing a change on some ALSA sequencer port on the system
*/
class DRUMSTICK_ALSA_EXPORT PortEvent : public ClientEvent
{
public:
/** Default constructor */
PortEvent() : ClientEvent() {}
/**
* Constructor from an ALSA event record
* @param event an ALSA event record
*/
explicit PortEvent(const snd_seq_event_t* event) : ClientEvent(event) {}
/**
* Gets the port number
* @return the port number
*/
int getPort() const { return m_event.data.addr.port; }
virtual PortEvent* clone() const override;
};
/**
* Auxiliary class to remove events from an ALSA queue
* @see MidiClient::removeEvents()
*/
class DRUMSTICK_ALSA_EXPORT RemoveEvents
{
public:
friend class MidiClient;
public:
RemoveEvents();
RemoveEvents(const RemoveEvents& other);
explicit RemoveEvents(snd_seq_remove_events_t* other);
virtual ~RemoveEvents();
RemoveEvents* clone();
RemoveEvents& operator=(const RemoveEvents& other);
int getSizeOfInfo() const;
int getChannel();
unsigned int getCondition();
const snd_seq_addr_t* getDest();
int getEventType();
int getQueue();
int getTag();
const snd_seq_timestamp_t* getTime();
void setChannel(int chan);
void setCondition(unsigned int cond);
void setDest(const snd_seq_addr_t* dest);
void setEventType(int type);
void setQueue(int queue);
void setTag(int tag);
void setTime(const snd_seq_timestamp_t* time);
private:
snd_seq_remove_events_t* m_Info;
};
/**
* Auxiliary class to translate between raw MIDI streams and ALSA events
*/
class DRUMSTICK_ALSA_EXPORT MidiCodec : public QObject
{
Q_OBJECT
public:
explicit MidiCodec(int bufsize, QObject* parent = nullptr);
~MidiCodec();
void init();
long decode(unsigned char *buf,
long count,
const snd_seq_event_t *ev);
long encode(const unsigned char *buf,
long count,
snd_seq_event_t *ev);
long encode(int c,
snd_seq_event_t *ev);
void enableRunningStatus(bool enable);
void resetEncoder();
void resetDecoder();
void resizeBuffer(int bufsize);
private:
snd_midi_event_t* m_Info;
};
/** @} */
}} /* namespace drumstick::ALSA */
Q_DECLARE_METATYPE(drumstick::ALSA::SequencerEvent)
Q_DECLARE_METATYPE(drumstick::ALSA::SequencerEvent*)
#endif //DRUMSTICK_ALSAEVENT_H
drumstick-2.9.0/library/include/drumstick/alsaqueue.h 0000644 0001750 0001750 00000014320 14541630232 021765 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_ALSAQUEUE_H
#define DRUMSTICK_ALSAQUEUE_H
#include
extern "C" {
#include
}
#include "macros.h"
namespace drumstick { namespace ALSA {
/**
* @file alsaqueue.h
* Classes managing ALSA Sequencer queues
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
class MidiClient;
class TimerId;
/**
* @addtogroup ALSAQueue ALSA Sequencer Queues
* @{
*
* @class QueueInfo
* Queue information container.
*
* This class is used to hold some properties about an ALSA queue object.
*/
class DRUMSTICK_ALSA_EXPORT QueueInfo
{
friend class MidiQueue;
public:
QueueInfo();
QueueInfo(const QueueInfo& other);
explicit QueueInfo(snd_seq_queue_info_t* other);
virtual ~QueueInfo();
QueueInfo* clone();
QueueInfo& operator=(const QueueInfo& other);
int getInfoSize() const;
int getId();
QString getName();
int getOwner();
bool isLocked();
unsigned int getFlags();
void setName(QString value);
void setOwner(int value);
void setLocked(bool locked);
void setFlags(unsigned int value);
private:
snd_seq_queue_info_t* m_Info;
};
/**
* Queue status container.
*
* This class is used to retrieve some status information from an ALSA queue.
*/
class DRUMSTICK_ALSA_EXPORT QueueStatus
{
friend class MidiQueue;
public:
QueueStatus();
QueueStatus(const QueueStatus& other);
explicit QueueStatus(snd_seq_queue_status_t* other);
virtual ~QueueStatus();
QueueStatus* clone();
QueueStatus& operator=(const QueueStatus& other);
int getInfoSize() const;
int getId();
int getEvents();
const snd_seq_real_time_t* getRealtime();
unsigned int getStatusBits();
bool isRunning();
double getClockTime();
snd_seq_tick_time_t getTickTime();
private:
snd_seq_queue_status_t* m_Info;
};
/**
* Queue tempo container.
*
* This class is used to hold some tempo properties of an ALSA queue object.
* The queue's resolution defines the meaning of the musical time, in ticks. It
* is expressed in PPQ (parts per quarter), or ticks in a quarter note (crotchet).
* The nominal tempo is usually expressed in BPM (beats per minute), or Maelzel
* metronome units. It can be also given in microseconds per beat. The tempo skew
* factor is given as two integer numbers: skew value and skew base, being the
* factor the quotient of both quantities = value / base. Currently (ALSA <= 1.0.20)
* you can only use the base constant 0x10000 (decimal 65536).
*/
class DRUMSTICK_ALSA_EXPORT QueueTempo
{
friend class MidiQueue;
public:
QueueTempo();
QueueTempo(const QueueTempo& other);
explicit QueueTempo(snd_seq_queue_tempo_t* other);
virtual ~QueueTempo();
QueueTempo* clone();
QueueTempo& operator=(const QueueTempo& other);
int getInfoSize() const;
int getId();
int getPPQ();
unsigned int getSkewValue();
unsigned int getSkewBase();
unsigned int getTempo();
void setPPQ(int value);
void setSkewValue(unsigned int value);
void setTempo(unsigned int value);
float getNominalBPM();
float getRealBPM();
void setTempoFactor(float value);
void setNominalBPM(float value);
protected:
void setSkewBase(unsigned int value);
private:
snd_seq_queue_tempo_t* m_Info;
};
/**
* Queue timer container.
*
* This class is used to hold some properties about the Timer used with an ALSA
* queue object.
*/
class DRUMSTICK_ALSA_EXPORT QueueTimer
{
friend class MidiQueue;
public:
QueueTimer();
QueueTimer(const QueueTimer& other);
explicit QueueTimer(snd_seq_queue_timer_t* other);
virtual ~QueueTimer();
QueueTimer* clone();
QueueTimer& operator=(const QueueTimer& other);
int getInfoSize() const;
int getQueueId();
snd_seq_queue_timer_type_t getType();
const snd_timer_id_t* getId();
unsigned int getResolution();
void setType(snd_seq_queue_timer_type_t value);
void setId(snd_timer_id_t* value);
void setId(const TimerId& id);
void setResolution(unsigned int value);
private:
snd_seq_queue_timer_t* m_Info;
};
/**
* Queue management.
*
* This class represents an ALSA sequencer queue object.
*/
class DRUMSTICK_ALSA_EXPORT MidiQueue : public QObject
{
Q_OBJECT
public:
explicit MidiQueue(MidiClient* seq, QObject* parent = nullptr);
MidiQueue(MidiClient* seq, const QueueInfo& info, QObject* parent = nullptr);
MidiQueue(MidiClient* seq, const QString name, QObject* parent = nullptr);
MidiQueue(MidiClient* seq, const int queue_id, QObject* parent = nullptr);
virtual ~MidiQueue();
int getId() const { return m_Id; }
void start();
void stop();
void continueRunning();
void clear();
void setTickPosition(snd_seq_tick_time_t pos);
void setRealTimePosition(snd_seq_real_time_t* pos);
QueueInfo& getInfo();
QueueStatus& getStatus();
QueueTempo& getTempo();
QueueTimer& getTimer();
int getUsage();
void setInfo(const QueueInfo& value);
void setTempo(const QueueTempo& value);
void setTimer(const QueueTimer& value);
void setUsage(int used);
private:
bool m_allocated;
int m_Id;
MidiClient* m_MidiClient;
QueueInfo m_Info;
QueueTempo m_Tempo;
QueueTimer m_Timer;
QueueStatus m_Status;
};
/** @} */
}} /* namespace drumstick::ALSA */
#endif //DRUMSTICK_ALSAQUEUE_H
drumstick-2.9.0/library/include/drumstick/backendmanager.h 0000644 0001750 0001750 00000007761 14541630232 022735 0 ustar pedro pedro /*
Drumstick RT (realtime MIDI In/Out)
Copyright (C) 2009-2023 Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef BACKENDMANAGER_H
#define BACKENDMANAGER_H
#include
#include
#include "macros.h"
#include "rtmidiinput.h"
#include "rtmidioutput.h"
/**
* @file backendmanager.h
* BackendManager class declaration
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_RT_EXPORT
#else
#if defined(drumstick_rt_EXPORTS)
#define DRUMSTICK_RT_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_RT_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick {
/**
* @ingroup RT
* @brief Drumstick Real-Time library
*/
namespace rt {
/**
* @addtogroup RT Realtime MIDI (I/O)
* @{
*/
/**
* @brief The BackendManager class manages lists of dynamic and static
* backends for applications based on drumstick-rt
*/
class DRUMSTICK_RT_EXPORT BackendManager
{
public:
/**
* @brief BackendManager constructor
*/
explicit BackendManager();
/**
* @brief ~BackendManager destructor
*/
virtual ~BackendManager();
/**
* @brief refresh the list of backends
*/
void refresh(QSettings *settings = nullptr);
/**
* @brief refresh the list of backends
*/
void refresh(const QVariantMap &map);
/**
* @brief availableInputs
* @return list of available MIDI inputs
*/
QList availableInputs();
/**
* @brief availableOutputs
* @return list of available MIDI outputs
*/
QList availableOutputs();
/**
* @brief defaultPaths
* @return list of paths for backends search
*/
QStringList defaultPaths();
/**
* @brief inputBackendByName
* @param name The name of some input backend
* @return Input backend instance if available
*/
MIDIInput *inputBackendByName(const QString name);
/**
* @brief outputBackendByName
* @param name The name of some output backend
* @return Output backend instance if available
*/
MIDIOutput *outputBackendByName(const QString name);
/**
* @brief findInput returns the backend corresponding
* to the provided name, or a suitable input instead.
* @param name The name of some input backend
* @return Input backend instance if available
*/
MIDIInput *findInput(QString name);
/**
* @brief findOutput returns the backend corresponding
* to the provided name, or a suitable output instead.
* @param name The name of some output backend
* @return Output backend instance if available
*/
MIDIOutput *findOutput(QString name);
static const QString QSTR_DRUMSTICK;
static const QString QSTR_DRUMSTICK_VERSION;
static const QString QSTR_DRUMSTICKRT;
static const QString QSTR_DRUMSTICKRT_GROUP;
static const QString QSTR_DRUMSTICKRT_PUBLICNAMEIN;
static const QString QSTR_DRUMSTICKRT_PUBLICNAMEOUT;
static const QString QSTR_DRUMSTICKRT_EXCLUDED;
static const QString QSTR_DRUMSTICKRT_PATH;
private:
class BackendManagerPrivate;
QScopedPointer d;
};
QString DRUMSTICK_RT_EXPORT drumstickLibraryVersion();
/** @} */
}} // namespace drumstick::rt
#endif // BACKENDMANAGER_H
drumstick-2.9.0/library/include/drumstick/macros.h 0000644 0001750 0001750 00000004316 14541630232 021270 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_MACROS_H
#define DRUMSTICK_MACROS_H
#include
/**
* @file macros.h
*/
#if defined(_MSC_VER)
#define DISABLE_WARNING_PUSH __pragma(warning( push ))
#define DISABLE_WARNING_POP __pragma(warning( pop ))
#define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber ))
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(4100)
#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(4505)
#define DISABLE_WARNING_DEPRECATED_DECLARATIONS DISABLE_WARNING(4996)
#elif defined(__GNUC__) || defined(__clang__)
#define DO_PRAGMA(X) _Pragma(#X)
#define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push)
#define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop)
#define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName)
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(-Wunused-parameter)
#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(-Wunused-function)
#define DISABLE_WARNING_DEPRECATED_DECLARATIONS DISABLE_WARNING(-Wdeprecated-declarations)
#else
#define DISABLE_WARNING_PUSH
#define DISABLE_WARNING_POP
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER
#define DISABLE_WARNING_UNREFERENCED_FUNCTION
#define DISABLE_WARNING_DEPRECATED_DECLARATIONS
#endif
#endif /* DRUMSTICK_MACROS_H */
drumstick-2.9.0/library/include/drumstick/pianopalette.h 0000644 0001750 0001750 00000007640 14541630232 022474 0 ustar pedro pedro /*
MIDI Virtual Piano Keyboard
Copyright (C) 2008-2023, Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef PIANOPALETTE_H
#define PIANOPALETTE_H
#include
#include
#include
#include
#include "macros.h"
/**
* @file pianopalette.h
* Piano Palette declarations
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_WIDGETS_EXPORT
#else
#if defined(drumstick_widgets_EXPORTS)
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick { namespace widgets {
/**
* @addtogroup Widgets
* @{
*
* @enum PalettePolicy
* @brief The PalettePolicy enumeration.
*
* This enum describes the different kind of color palettes supported, which
* can be used for highlight, background or foreground colors.
*/
enum PalettePolicy {
PAL_SINGLE = 0, ///< Single highlihgting color for all keys
PAL_DOUBLE = 1, ///< Two highlihgting colors (naturals/alterations)
PAL_CHANNELS = 2, ///< Different highlihgting colors for each channel
PAL_SCALE = 3, ///< Background colors for each chromatic scale note
PAL_KEYS = 4, ///< Two background colors (naturals/alterations)
PAL_FONT = 5, ///< Foreground font colors for names
PAL_HISCALE = 6 ///< Highlighting colors for each chromatic scale note
};
/**
* @brief The PianoPalette class
*
* PianoPalette represents a set of colors used to paint the PianoKeybd widgets
*/
class DRUMSTICK_WIDGETS_EXPORT PianoPalette
{
Q_GADGET
Q_DECLARE_TR_FUNCTIONS(PianoPalette)
Q_ENUM(PalettePolicy)
public:
explicit PianoPalette(const int id);
virtual ~PianoPalette() = default;
void resetColors();
void retranslateStrings();
int paletteId() const;
int getNumColors() const;
bool isHighLight() const;
bool isBackground() const;
bool isForeground() const;
QString paletteName() const;
void setPaletteName(const QString& name);
QString paletteText() const;
void setPaletteText(const QString& text);
QColor getColor(const int i) const;
void setColor(const int n, const QString& s, const QColor& c);
void setColor(const int n, const QColor& c);
QString getColorName(const int i) const;
void setColorName(const int n, const QString& s);
void saveColors() const;
void loadColors();
bool operator==(const PianoPalette& other) const;
bool operator!=(const PianoPalette& other) const;
static const QString QSTR_PALETTEPREFIX;
friend QDataStream &operator<<(QDataStream& stream, const PianoPalette& palette);
friend QDataStream &operator>>(QDataStream& stream, PianoPalette& palette);
protected:
void initialize();
void resetPaletteSingle();
void resetPaletteDouble();
void resetPaletteChannels();
void resetPaletteScale();
void resetPaletteKeys();
void resetPaletteFont();
void retranslatePaletteSingle();
void retranslatePaletteDouble();
void retranslatePaletteChannels();
void retranslatePaletteScale();
void retranslatePaletteKeys();
void retranslatePaletteFont();
int m_paletteId;
QList m_colors;
QList m_names;
QString m_paletteName;
QString m_paletteText;
};
/** @} */
}} // namespace drumstick::widgets
#endif // PIANOPALETTE_H
drumstick-2.9.0/library/include/drumstick/qwrk.h 0000644 0001750 0001750 00000052575 14541630232 021002 0 ustar pedro pedro /*
WRK File component
Copyright (C) 2010-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_QWRK_H
#define DRUMSTICK_QWRK_H
#include "macros.h"
#include
#include
class QTextCodec;
class QDataStream;
/**
* @file qwrk.h
* Cakewalk WRK Files Input
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_FILE_EXPORT
#else
#if defined(drumstick_file_EXPORTS)
#define DRUMSTICK_FILE_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_FILE_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick { namespace File {
/**
* @addtogroup WRK Cakewalk WRK File Parser (Input)
* @{
*
* @enum WrkChunkType
* Record types within a WRK file
*/
enum WrkChunkType {
TRACK_CHUNK = 1, ///< Track prefix
STREAM_CHUNK = 2, ///< Events stream
VARS_CHUNK = 3, ///< Global variables
TEMPO_CHUNK = 4, ///< Tempo map
METER_CHUNK = 5, ///< Meter map
SYSEX_CHUNK = 6, ///< System exclusive bank
MEMRGN_CHUNK = 7, ///< Memory region
COMMENTS_CHUNK = 8, ///< Comments
TRKOFFS_CHUNK = 9, ///< Track offset
TIMEBASE_CHUNK = 10, ///< Timebase. If present is the first chunk in the file.
TIMEFMT_CHUNK = 11, ///< SMPTE time format
TRKREPS_CHUNK = 12, ///< Track repetitions
TRKPATCH_CHUNK = 14, ///< Track patch
NTEMPO_CHUNK = 15, ///< New Tempo map
THRU_CHUNK = 16, ///< Extended thru parameters
LYRICS_CHUNK = 18, ///< Events stream with lyrics
TRKVOL_CHUNK = 19, ///< Track volume
SYSEX2_CHUNK = 20, ///< System exclusive bank
MARKERS_CHUNK = 21, ///< Markers
STRTAB_CHUNK = 22, ///< Table of text event types
METERKEY_CHUNK = 23, ///< Meter/Key map
TRKNAME_CHUNK = 24, ///< Track name
VARIABLE_CHUNK = 26, ///< Variable record chunk
NTRKOFS_CHUNK = 27, ///< Track offset
TRKBANK_CHUNK = 30, ///< Track bank
NTRACK_CHUNK = 36, ///< Track prefix
NSYSEX_CHUNK = 44, ///< System exclusive bank
NSTREAM_CHUNK = 45, ///< Events stream
SGMNT_CHUNK = 49, ///< Segment prefix
SOFTVER_CHUNK = 74, ///< Software version which saved the file
END_CHUNK = 255 ///< Last chunk, end of file
};
/**
* Cakewalk WRK file format (input only)
*
* This class is used to parse Cakewalk WRK Files.
* Signals with QString parameters are deprecated because the class QTextCodec was removed from QtCore since Qt6.
*
* @since 0.3.0
*/
class DRUMSTICK_FILE_EXPORT QWrk : public QObject
{
Q_OBJECT
Q_ENUM(WrkChunkType)
public:
explicit QWrk(QObject * parent = nullptr);
virtual ~QWrk();
void readFromStream(QDataStream *stream);
void readFromFile(const QString& fileName);
Q_DECL_DEPRECATED QTextCodec* getTextCodec();
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec);
long getFilePos();
int getNow() const;
int getFrom() const;
int getThru() const;
int getKeySig() const;
int getClock() const;
int getAutoSave() const;
int getPlayDelay() const;
bool getZeroCtrls() const;
bool getSendSPP() const;
bool getSendCont() const;
bool getPatchSearch() const;
bool getAutoStop() const;
unsigned int getStopTime() const;
bool getAutoRewind() const;
int getRewindTime() const;
bool getMetroPlay() const;
bool getMetroRecord() const;
bool getMetroAccent() const;
int getCountIn() const;
bool getThruOn() const;
bool getAutoRestart() const;
int getCurTempoOfs() const;
int getTempoOfs1() const;
int getTempoOfs2() const;
int getTempoOfs3() const;
bool getPunchEnabled() const;
int getPunchInTime() const;
int getPunchOutTime() const;
int getEndAllTime() const;
QByteArray getLastChunkRawData() const;
double getRealTime(long ticks) const;
/**
* Cakewalk WRK file format header string id
*/
static const QByteArray HEADER; ///< Cakewalk WRK File header id
Q_SIGNALS:
/**
* Emitted for a WRK file read error
*
* @param errorStr Error string
*/
void signalWRKError(const QString& errorStr);
/**
* Emitted after reading an unknown chunk
*
* @param type chunk type
* @param data chunk data (not decoded)
*/
void signalWRKUnknownChunk(int type, const QByteArray& data);
/**
* Emitted after reading a WRK header
*
* @param verh WRK file format version major
* @param verl WRK file format version minor
*/
void signalWRKHeader(int verh, int verl);
/**
* Emitted after reading the last chunk of a WRK file
*/
void signalWRKEnd();
/**
* Emitted after reading the last event of a event stream
* @param time musical time
*/
void signalWRKStreamEnd(long time);
/**
* Emitted after reading a Note message
*
* @param track track number
* @param time musical time
* @param chan MIDI Channel
* @param pitch MIDI Note
* @param vol Velocity
* @param dur Duration
*/
void signalWRKNote(int track, long time, int chan, int pitch, int vol, int dur);
/**
* Emitted after reading a Polyphonic Aftertouch message
*
* @param track track number
* @param time musical time
* @param chan MIDI Channel
* @param pitch MIDI Note
* @param press Pressure amount
*/
void signalWRKKeyPress(int track, long time, int chan, int pitch, int press);
/**
* Emitted after reading a Control Change message
*
* @param track track number
* @param time musical time
* @param chan MIDI Channel
* @param ctl MIDI Controller
* @param value Control value
*/
void signalWRKCtlChange(int track, long time, int chan, int ctl, int value);
/**
* Emitted after reading a Bender message
*
* @param track track number
* @param time musical time
* @param chan MIDI Channel
* @param value Bender value
*/
void signalWRKPitchBend(int track, long time, int chan, int value);
/**
* Emitted after reading a Program change message
*
* @param track track number
* @param time musical time
* @param chan MIDI Channel
* @param patch Program number
*/
void signalWRKProgram(int track, long time, int chan, int patch);
/**
* Emitted after reading a Channel Aftertouch message
*
* @param track track number
* @param time musical time
* @param chan MIDI Channel
* @param press Pressure amount
*/
void signalWRKChanPress(int track, long time, int chan, int press);
/**
* Emitted after reading a System Exclusive event
*
* @param track track number
* @param time musical time
* @param bank Sysex Bank number
*/
void signalWRKSysexEvent(int track, long time, int bank);
/**
* Emitted after reading a System Exclusive Bank
*
* @param bank Sysex Bank number
* @param name Sysex Bank name
* @param autosend Send automatically after loading the song
* @param port MIDI output port
* @param data Sysex bytes
*/
void signalWRKSysex(int bank, const QString& name, bool autosend, int port, const QByteArray& data);
/**
* Emitted after reading a text message
*
* @param track track number
* @param time musical time
* @param type Text type
* @param data Text data
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKText2() instead
*/
Q_DECL_DEPRECATED void signalWRKText(int track, long time, int type, const QString& data);
/**
* Emitted after reading a WRK Time signature
*
* @param bar Measure number
* @param num Numerator
* @param den Denominator (exponent in a power of two)
*/
void signalWRKTimeSig(int bar, int num, int den);
/**
* Emitted after reading a WRK Key Signature
*
* @param bar Measure number
* @param alt Number of alterations (negative=flats, positive=sharps)
*/
void signalWRKKeySig(int bar, int alt);
/**
* Emitted after reading a Tempo Change message.
*
* Tempo units are given in beats * 100 per minute, so to obtain BPM
* it is necessary to divide by 100 the tempo.
*
* @param time musical time
* @param tempo beats per minute multiplied by 100
*/
void signalWRKTempo(long time, int tempo);
/**
* Emitted after reading a track prefix chunk
*
* @param name1 track 1st name
* @param name2 track 2nd name
* @param trackno track number
* @param channel track forced channel (-1=no forced)
* @param pitch track pitch transpose in semitones (-127..127)
* @param velocity track velocity increment (-127..127)
* @param port track forced port
* @param selected true if track is selected
* @param muted true if track is muted
* @param loop true if loop is enabled
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKTrack2() instead
*/
Q_DECL_DEPRECATED
void signalWRKTrack(const QString& name1,
const QString& name2,
int trackno, int channel, int pitch,
int velocity, int port,
bool selected, bool muted, bool loop );
/**
* Emitted after reading the timebase chunk
*
* @param timebase ticks per quarter note
*/
void signalWRKTimeBase(int timebase);
/**
* Emitted after reading the global variables chunk.
*
* This record contains miscellaneous Cakewalk global variables that can
* be retrieved using individual getters.
*
* @see getNow(), getFrom(), getThru()
*/
void signalWRKGlobalVars();
/**
* Emitted after reading an Extended Thru parameters chunk.
*
* It was introduced in Cakewalk version 4.0. These parameters are
* intended to override the global vars Thruon value, so this record should
* come after the VARS_CHUNK record. It is optional.
*
* @param mode (auto, off, on)
* @param port MIDI port
* @param channel MIDI channel
* @param keyPlus Note transpose
* @param velPlus Velocity transpose
* @param localPort MIDI local port
*/
void signalWRKThru(int mode, int port, int channel, int keyPlus, int velPlus, int localPort);
/**
* Emitted after reading a track offset chunk
*
* @param track track number
* @param offset time offset
*/
void signalWRKTrackOffset(int track, int offset);
/**
* Emitted after reading a track offset chunk
*
* @param track track number
* @param reps number of repetitions
*/
void signalWRKTrackReps(int track, int reps);
/**
* Emitted after reading a track patch chunk
*
* @param track track number
* @param patch
*/
void signalWRKTrackPatch(int track, int patch);
/**
* Emitted after reading a track bank chunk
*
* @param track track number
* @param bank
*/
void signalWRKTrackBank(int track, int bank);
/**
* Emitted after reading a SMPTE time format chunk
*
* @param frames frames/sec (24, 25, 29=30-drop, 30)
* @param offset frames of offset
*/
void signalWRKTimeFormat(int frames, int offset);
/**
* Emitted after reading a comments chunk
*
* @param data file text comments
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKComments2() instead
*/
Q_DECL_DEPRECATED void signalWRKComments(const QString& data);
/**
* Emitted after reading a variable chunk.
* This record may contain data in text or binary format.
*
* @param name record identifier
* @param data record variable data
*/
void signalWRKVariableRecord(const QString& name, const QByteArray& data);
/**
* Emitted after reading a track volume chunk.
*
* @param track track number
* @param vol initial volume
*/
void signalWRKTrackVol(int track, int vol);
/**
* Emitted after reading a new track prefix
*
* @param name track name
* @param trackno track number
* @param channel forced MIDI channel
* @param pitch Note transposition
* @param velocity Velocity increment
* @param port MIDI port number
* @param selected track is selected
* @param muted track is muted
* @param loop track loop enabled
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKNewTrack2() instead
*/
Q_DECL_DEPRECATED
void signalWRKNewTrack( const QString& name,
int trackno, int channel, int pitch,
int velocity, int port,
bool selected, bool muted, bool loop );
/**
* Emitted after reading a software version chunk.
*
* @param version software version string
*/
void signalWRKSoftVer(const QString& version);
/**
* Emitted after reading a track name chunk.
*
* @param track track number
* @param name track name
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKTrackName2() instead
*/
Q_DECL_DEPRECATED void signalWRKTrackName(int track, const QString& name);
/**
* Emitted after reading a string event types chunk.
*
* @param strs list of declared string event types
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKStringTable2() instead
*/
Q_DECL_DEPRECATED void signalWRKStringTable(const QStringList& strs);
/**
* Emitted after reading a segment prefix chunk.
*
* @param track track number
* @param time segment time offset
* @param name segment name
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKSegment2() instead
*/
Q_DECL_DEPRECATED void signalWRKSegment(int track, long time, const QString& name);
/**
* Emitted after reading a chord diagram chunk.
*
* @param track track number
* @param time event time in ticks
* @param name chord name
* @param data chord data definition (not decoded)
*/
void signalWRKChord(int track, long time, const QString& name, const QByteArray& data);
/**
* Emitted after reading an expression indication (notation) chunk.
*
* @param track track number
* @param time event time in ticks
* @param code expression event code
* @param text expression text
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKExpression2() instead
*/
Q_DECL_DEPRECATED void signalWRKExpression(int track, long time, int code, const QString& text);
/**
* Emitted after reading a hairpin symbol (notation) chunk.
*
* @param track track number
* @param time event time in ticks
* @param code hairpin code
* @param dur duration
*/
void signalWRKHairpin(int track, long time, int code, int dur);
/**
* Emitted after reading a text message
* This signal is emitted when getTextCodec() is nullptr
*
* @param track track number
* @param time musical time
* @param type Text type
* @param data Text data
*/
void signalWRKText2(int track, long time, int type, const QByteArray& data);
/**
* Emitted after reading a track prefix chunk
* This signal is emitted when getTextCodec() is nullptr
*
* @param name1 track 1st name
* @param name2 track 2nd name
* @param trackno track number
* @param channel track forced channel (-1=no forced)
* @param pitch track pitch transpose in semitones (-127..127)
* @param velocity track velocity increment (-127..127)
* @param port track forced port
* @param selected true if track is selected
* @param muted true if track is muted
* @param loop true if loop is enabled
*/
void signalWRKTrack2(const QByteArray& name1,
const QByteArray& name2,
int trackno, int channel, int pitch,
int velocity, int port,
bool selected, bool muted, bool loop );
/**
* Emitted after reading a comments chunk
* This signal is emitted when getTextCodec() is nullptr
*
* @param data file text comments
*/
void signalWRKComments2(const QByteArray& data);
/**
* Emitted after reading a new track prefix
* This signal is emitted when getTextCodec() is nullptr
*
* @param name track name
* @param trackno track number
* @param channel forced MIDI channel
* @param pitch Note transposition
* @param velocity Velocity increment
* @param port MIDI port number
* @param selected track is selected
* @param muted track is muted
* @param loop track loop enabled
*/
void signalWRKNewTrack2(const QByteArray& name,
int trackno, int channel, int pitch,
int velocity, int port,
bool selected, bool muted, bool loop );
/**
* Emitted after reading a track name chunk.
* This signal is emitted when getTextCodec() is nullptr
*
* @param track track number
* @param name track name
*/
void signalWRKTrackName2(int track, const QByteArray& name);
/**
* Emitted after reading a string event types chunk.
* This signal is emitted when getTextCodec() is nullptr
*
* @param strs list of declared string event types
*/
void signalWRKStringTable2(const QList& strs);
/**
* Emitted after reading a segment prefix chunk.
* This signal is emitted when getTextCodec() is nullptr
*
* @param track track number
* @param time segment time offset
* @param name segment name
*/
void signalWRKSegment2(int track, long time, const QByteArray& name);
/**
* Emitted after reading an expression indication (notation) chunk.
* This signal is emitted when getTextCodec() is nullptr
*
* @param track track number
* @param time event time in ticks
* @param code expression event code
* @param text expression text
*/
void signalWRKExpression2(int track, long time, int code, const QByteArray& text);
/**
* Emitted after reading a text marker
* This is deprecated because the class QTextCodec was removed from QtCore since Qt6
* Use signalWRKMarker2() instead
*
* @param time event time in ticks or smpte
* @param type tipe of time: 0=ticks or 1=smpte
* @param data marker text
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalWRKMarker2() instead
*/
Q_DECL_DEPRECATED void signalWRKMarker(long time, int type, const QString& data);
/**
* Emitted after reading a text marker
* This signal is emitted when getTextCodec() is nullptr
*
* @param time event time in ticks or smpte
* @param type tipe of time: 0=ticks or 1=smpte
* @param data marker text
*/
void signalWRKMarker2(long time, int type, const QByteArray& data);
private:
quint8 readByte();
quint16 to16bit(quint8 c1, quint8 c2);
quint32 to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4);
quint16 read16bit();
quint32 read24bit();
quint32 read32bit();
QString readString(int len);
QString readVarString();
void readRawData(int size);
void readGap(int size);
bool atEnd();
void seek(qint64 pos);
int readChunk();
void processTrackChunk();
void processVarsChunk();
void processTimebaseChunk();
void processNoteArray(int track, int events);
void processStreamChunk();
void processMeterChunk();
void processTempoChunk(int factor = 1);
void processSysexChunk();
void processSysex2Chunk();
void processNewSysexChunk();
void processThruChunk();
void processTrackOffset();
void processTrackReps();
void processTrackPatch();
void processTrackBank();
void processTimeFormat();
void processComments();
void processVariableRecord(int max);
void processNewTrack();
void processSoftVer();
void processTrackName();
void processStringTable();
void processLyricsStream();
void processTrackVol();
void processNewTrackOffset();
void processMeterKeyChunk();
void processSegmentChunk();
void processNewStream();
void processUnknown(int id);
void processEndChunk();
void wrkRead();
QByteArray readByteArray(int len);
QByteArray readVarByteArray();
void processMarkers();
struct RecTempo {
long time;
double tempo;
double seconds;
};
class QWrkPrivate;
QScopedPointer d;
};
/** @} */
}} // namespace drumstick::File
#endif // DRUMSTICK_QWRK_H
drumstick-2.9.0/library/include/drumstick/rtmidiinput.h 0000644 0001750 0001750 00000012320 14541630232 022346 0 ustar pedro pedro /*
Drumstick MIDI realtime input-output
Copyright (C) 2009-2023 Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef MIDIINPUT_H
#define MIDIINPUT_H
#include
#include
#include
#include
#include
#include "macros.h"
#include "rtmidioutput.h"
/**
* @file rtmidiinput.h
* Realtime MIDI input interface
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_RT_EXPORT
#else
#if defined(drumstick_rt_EXPORTS)
#define DRUMSTICK_RT_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_RT_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick { namespace rt {
/**
* @addtogroup RT
* @{
*
* @class MIDIInput
* @brief MIDI IN interface
*/
class DRUMSTICK_RT_EXPORT MIDIInput : public QObject
{
Q_OBJECT
public:
/**
* @brief MIDIInput constructor
* @param parent
*/
explicit MIDIInput(QObject *parent = nullptr)
: QObject(parent)
{}
/**
* @brief ~MIDIInput destructor
*/
virtual ~MIDIInput() = default;
/**
* @brief initialize
* @param settings
*/
virtual void initialize(QSettings *settings) = 0;
/**
* @brief backendName
* @return plugin name
*/
virtual QString backendName() = 0;
/**
* @brief publicName
* @return MIDI port name
*/
virtual QString publicName() = 0;
/**
* @brief setPublicName
* @param name MIDI port name
*/
virtual void setPublicName(QString name) = 0;
/**
* @brief connections
* @param advanced whether the advanced connections are included or not
* @return list of available MIDI ports
*/
virtual QList connections(bool advanced = false) = 0;
/**
* @brief setExcludedConnections
* @param conns
*/
virtual void setExcludedConnections(QStringList conns) = 0;
/**
* @brief open the MIDI port by name
* @param conn Connection to open
*/
virtual void open(const MIDIConnection &conn) = 0;
/**
* @brief close the MIDI port
*/
virtual void close() = 0;
/**
* @brief currentConnection
* @return name of the current connection if it is opened
*/
virtual MIDIConnection currentConnection() = 0;
/**
* @brief setMIDIThruDevice
* @param device
*/
virtual void setMIDIThruDevice(MIDIOutput *device) = 0;
/**
* @brief enableMIDIThru
* @param enable
*/
virtual void enableMIDIThru(bool enable) = 0;
/**
* @brief isEnabledMIDIThru
* @return MIDI Thru is enabled
*/
virtual bool isEnabledMIDIThru() = 0;
Q_SIGNALS:
/**
* @brief midiNoteOff 0x8
* @param chan
* @param note
* @param vel
*/
void midiNoteOff(const int chan, const int note, const int vel);
/**
* @brief midiNoteOn 0x9
* @param chan
* @param note
* @param vel
*/
void midiNoteOn(const int chan, const int note, const int vel);
/**
* @brief midiKeyPressure 0xA
* @param chan
* @param note
* @param value
*/
void midiKeyPressure(const int chan, const int note, const int value);
/**
* @brief midiController 0xB
* @param chan
* @param control
* @param value
*/
void midiController(const int chan, const int control, const int value);
/**
* @brief midiProgram 0xC
* @param chan
* @param program
*/
void midiProgram(const int chan, const int program);
/**
* @brief midiChannelPressure 0xD
* @param chan
* @param value
*/
void midiChannelPressure(const int chan, const int value);
/**
* @brief midiPitchBend 0xE
* @param chan
* @param value
*/
void midiPitchBend(const int chan, const int value);
/**
* @brief midiSysex
* @param data 0xF0 ... 0xF7
*/
void midiSysex(const QByteArray &data);
/**
* @brief midiSystemCommon
* @param status 0xF (1..6)
*/
void midiSystemCommon(const int status);
/**
* @brief midiSystemRealtime
* @param status 0xF (8..F)
*/
void midiSystemRealtime(const int status);
};
/** @} */
}} // namespace drumstick::rt
Q_DECLARE_INTERFACE(drumstick::rt::MIDIInput, "net.sourceforge.drumstick.rt.MIDIInput/2.0")
#endif // MIDIINPUT_H
drumstick-2.9.0/library/include/drumstick/rtmidioutput.h 0000644 0001750 0001750 00000021272 14541630232 022555 0 ustar pedro pedro /*
Drumstick MIDI realtime input-output
Copyright (C) 2009-2023 Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef MIDIOUTPUT_H
#define MIDIOUTPUT_H
#include
#include
#include
#include
#include
#include "macros.h"
/**
* @file rtmidioutput.h
* Realtime MIDI output interface
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_RT_EXPORT
#else
#if defined(drumstick_rt_EXPORTS)
#define DRUMSTICK_RT_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_RT_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick { namespace rt {
/**
* @addtogroup RT
* @{
*/
const quint8 MIDI_STD_CHANNELS = 16; ///< Standard number of MIDI channels
const quint8 MIDI_GM_STD_DRUM_CHANNEL = (10-1); ///< Number of the GM percussion channel
const quint8 MIDI_CONTROL_MSB_BANK_SELECT = 0x00; ///< MIDI Controller number for MSB Bank number
const quint8 MIDI_CONTROL_MSB_MAIN_VOLUME = 0x07; ///< MIDI Controller number for MSB volume
const quint8 MIDI_CONTROL_LSB_BANK_SELECT = 0x20; ///< MIDI Controller number for LSB Bank number
const quint8 MIDI_CONTROL_REVERB_SEND = 0x5b; ///< MIDI Controller number for Reverb send
const quint8 MIDI_CONTROL_ALL_SOUNDS_OFF = 0x78; ///< MIDI Controller number for All sounds off
const quint8 MIDI_CONTROL_ALL_NOTES_OFF = 0x7b; ///< MIDI Controller number for All notes off
const quint8 MIDI_CONTROL_RESET_CONTROLLERS = 0x79; ///< MIDI Controller number for Reset all controllers
const quint8 MIDI_STATUS_NOTEOFF = 0x80; ///< MIDI status byte for NOTE OFF messages
const quint8 MIDI_STATUS_NOTEON = 0x90; ///< MIDI status byte for NOTE ON messages
const quint8 MIDI_STATUS_KEYPRESURE = 0xa0; ///< MIDI status byte for KEY pressure messages
const quint8 MIDI_STATUS_CONTROLCHANGE = 0xb0; ///< MIDI status byte for CONTROL change messages
const quint8 MIDI_STATUS_PROGRAMCHANGE = 0xc0; ///< MIDI status byte for PROGRAM change messages
const quint8 MIDI_STATUS_CHANNELPRESSURE = 0xd0; ///< MIDI status byte for CHANNEL PRESSURE messages
const quint8 MIDI_STATUS_PITCHBEND = 0xe0; ///< MIDI status byte for PITCH bend messages
const quint8 MIDI_STATUS_SYSEX = 0xf0; ///< MIDI status byte for System Exclusive START messages
const quint8 MIDI_STATUS_ENDSYSEX = 0xf7; ///< MIDI status byte for System Exclusive END messages
const quint8 MIDI_STATUS_REALTIME = 0xf8; ///< Minimum value for MIDI Realtime messages status
const quint8 MIDI_STATUS_MASK = 0xf0; ///< Mask to extract the MIDI status byte from a MIDI message
const quint8 MIDI_CHANNEL_MASK = 0x0f; ///< Mask to extract the MIDI channel byte from a MIDI message
const quint8 MIDI_COMMON_QTRFRAME = 0xF1; ///< MIDI Quarter frame status message
const quint8 MIDI_COMMON_SONGPP = 0xF2; ///< MIDI Song Position status message
const quint8 MIDI_COMMON_SONGSELECT = 0xF3; ///< MIDI Song Select status message
const quint8 MIDI_COMMON_TUNEREQ = 0xF6; ///< MIDI Tune Request status message
const quint8 MIDI_REALTIME_CLOCK = 0xF8; ///< MIDI Clock status message
const quint8 MIDI_REALTIME_START = 0xFA; ///< MIDI Start status message
const quint8 MIDI_REALTIME_CONTINUE = 0xFB; ///< MIDI Continue status message
const quint8 MIDI_REALTIME_STOP = 0xFC; ///< MIDI Stop status message
const quint8 MIDI_REALTIME_SENSING = 0xFE; ///< MIDI Active Sensing status message
const quint8 MIDI_REALTIME_RESET = 0xFF; ///< MIDI Reset status message
/**
* @brief MIDI_LSB is a function to extract the least significative byte of a MIDI value
* @param x a MIDI integer value
* @return the least significative byte of the input value
*/
inline int MIDI_LSB(int x)
{
return (x % 0x80);
}
/**
* @brief MIDI_MSB is a function to extract the most significative byte of a MIDI value
* @param x MIDI integer value
* @return the most significative byte of the input value
*/
inline int MIDI_MSB(int x)
{
return (x / 0x80);
}
/**
* @brief MIDIConnection represents a connection identifier
*
* MIDIConnection is an alias for QPair where the
* first component is a QString representing the symbolic name of the MIDI Port
* and the second component is a QVariant that represents the native identification
* of the MIDI port, which may be a string, a number, or any other data type
* accepted as a QVariant.
*/
typedef QPair MIDIConnection;
/**
* @brief MIDI OUT interface
*/
class DRUMSTICK_RT_EXPORT MIDIOutput : public QObject
{
Q_OBJECT
public:
/**
* @brief MIDIOutput constructor
* @param parent
*/
explicit MIDIOutput(QObject *parent = nullptr) : QObject(parent) {}
/**
* @brief ~MIDIOutput destructor
*/
virtual ~MIDIOutput() = default;
/**
* @brief initialize
* @param settings
*/
virtual void initialize(QSettings* settings) = 0;
/**
* @brief backendName
* @return plugin name
*/
virtual QString backendName() = 0;
/**
* @brief publicName
* @return MIDI port name
*/
virtual QString publicName() = 0;
/**
* @brief setPublicName
* @param name MIDI port name
*/
virtual void setPublicName(QString name) = 0;
/**
* @brief connections
* @param advanced whether the advanced connections are included or not
* @return list of available MIDI ports
*/
virtual QList connections(bool advanced = false) = 0;
/**
* @brief setExcludedConnections
* @param conns
*/
virtual void setExcludedConnections(QStringList conns) = 0;
/**
* @brief open the MIDI port by name
* @param conn the MIDI connection to be opened
*/
virtual void open(const MIDIConnection& conn) = 0;
/**
* @brief close the MIDI port
*/
virtual void close() = 0;
/**
* @brief currentConnection
* @return name of the current connection if it is opened
*/
virtual MIDIConnection currentConnection() = 0;
public Q_SLOTS:
/**
* @brief sendNoteOff 0x8
* @param chan
* @param note
* @param vel
*/
virtual void sendNoteOff(int chan, int note, int vel) = 0;
/**
* @brief sendNoteOn 0x9
* @param chan
* @param note
* @param vel
*/
virtual void sendNoteOn(int chan, int note, int vel) = 0;
/**
* @brief sendKeyPressure 0xA
* @param chan
* @param note
* @param value
*/
virtual void sendKeyPressure(int chan, int note, int value) = 0;
/**
* @brief sendController 0xB
* @param chan
* @param control
* @param value
*/
virtual void sendController(int chan, int control, int value) = 0;
/**
* @brief sendProgram 0xC
* @param chan
* @param program
*/
virtual void sendProgram(int chan, int program) = 0;
/**
* @brief sendChannelPressure 0xD
* @param chan
* @param value
*/
virtual void sendChannelPressure(int chan, int value) = 0;
/**
* @brief sendPitchBend 0xE
* @param chan
* @param value
*/
virtual void sendPitchBend(int chan, int value) = 0;
/**
* @brief sendSysex
* @param data 0xF0 ... 0xF7
*/
virtual void sendSysex(const QByteArray& data) = 0;
/**
* @brief sendSystemMsg
* @param status 0xF
*/
virtual void sendSystemMsg(const int status) = 0;
};
/** @} */
}} // namespace drumstick::rt
Q_DECLARE_INTERFACE(drumstick::rt::MIDIOutput, "net.sourceforge.drumstick.rt.MIDIOutput/2.0")
Q_DECLARE_METATYPE(drumstick::rt::MIDIConnection)
#endif /* MIDIOUTPUT_H */
drumstick-2.9.0/library/include/drumstick/sequencererror.h 0000644 0001750 0001750 00000005164 14541630232 023052 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef SEQUENCERERROR_H
#define SEQUENCERERROR_H
#include
#include "macros.h"
#include
/**
* @file sequencererror.h
* SequencerError Exception class
*/
/**
* @namespace std
* C++ Standard Library namespace
*
* @class std::exception
* Provides consistent interface to handle errors.
* @see https://en.cppreference.com/w/cpp/error/exception
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick {
namespace ALSA {
/**
* @addtogroup ALSAError ALSA Sequencer Exception
* @{
*
* @class SequencerError
* Exception class for ALSA Sequencer errors.
* This class is used to report errors from the ALSA sequencer.
*
* The class SequencerError represents an exception object reported when the
* ALSA library returns an error code. It is only used for severe errors.
*/
class DRUMSTICK_ALSA_EXPORT SequencerError : std::exception
{
public:
/**
* Constructor
* @param s Error location
* @param rc Numeric error code
*/
SequencerError(QString const& s, int rc);
/**
* Retrieve a human readable error message
* @return human readable error message
*/
virtual const char* what() const noexcept override;
/**
* Gets the human readable error message from the error code
* @return Error message
*/
QString qstrError() const;
/**
* Gets the numeric error code
* @return Error code
*/
int code() const;
/**
* Gets the location of the error code as provided in the constructor
* @return Error location
*/
const QString& location() const;
private:
QString m_location;
int m_errCode;
};
/** @} */
} // namespace ALSA
} // namespace drumstick
#endif // SEQUENCERERROR_H
drumstick-2.9.0/library/include/drumstick/subscription.h 0000644 0001750 0001750 00000007132 14541630232 022527 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_SUBSCRIPTION_H
#define DRUMSTICK_SUBSCRIPTION_H
extern "C" {
#include
}
#include
#include "macros.h"
namespace drumstick { namespace ALSA {
/**
* @file subscription.h
* Classes managing ALSA sequencer subscriptions
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
class MidiClient;
/**
* @addtogroup ALSASubs ALSA Sequencer Subscriptions
* @{
*
* @class Subscriber
* Subscriber container class.
*
* This class is used to enumerate the subscribers of a given (root) port.
*/
class DRUMSTICK_ALSA_EXPORT Subscriber
{
friend class PortInfo;
public:
Subscriber();
Subscriber(const Subscriber& other);
explicit Subscriber(snd_seq_query_subscribe_t* other);
virtual ~Subscriber();
Subscriber* clone();
int getSizeOfInfo() const;
int getClient();
int getPort();
const snd_seq_addr_t* getRoot();
snd_seq_query_subs_type_t getType();
int getIndex();
int getNumSubs();
const snd_seq_addr_t* getAddr();
int getQueue();
bool getExclusive();
bool getTimeUpdate();
bool getTimeReal();
void setClient(int client);
void setPort(int port);
void setRoot(snd_seq_addr_t* addr);
void setType(snd_seq_query_subs_type_t type);
void setIndex(int index);
Subscriber& operator=(const Subscriber& other);
private:
snd_seq_query_subscribe_t* m_Info;
};
/**
* Subscription management.
*
* This class represents a connection between two ports.
*/
class DRUMSTICK_ALSA_EXPORT Subscription
{
public:
Subscription();
Subscription(const Subscription& other);
explicit Subscription(snd_seq_port_subscribe_t* other);
explicit Subscription(MidiClient* seq);
virtual ~Subscription();
Subscription* clone();
int getSizeOfInfo() const;
void setSender(unsigned char client, unsigned char port);
void setDest(unsigned char client, unsigned char port);
void subscribe(MidiClient* seq);
void unsubscribe(MidiClient* seq);
const snd_seq_addr_t* getSender();
const snd_seq_addr_t* getDest();
int getQueue();
bool getExclusive();
bool getTimeUpdate();
bool getTimeReal();
void setSender(const snd_seq_addr_t* addr);
void setDest(const snd_seq_addr_t* addr);
void setQueue(int queue);
void setExclusive(bool val);
void setTimeUpdate(bool val);
void setTimeReal(bool val);
Subscription& operator=(const Subscription& other);
private:
snd_seq_port_subscribe_t* m_Info;
};
/**
* List of subscriptions
*/
typedef QList SubscriptionsList;
/**
* List of subscribers
*/
typedef QList SubscribersList;
/** @} */
}} /* namespace drumstick::ALSA */
#endif //DRUMSTICK_SUBSCRIPTION_H
drumstick-2.9.0/library/include/drumstick/configurationdialogs.h 0000644 0001750 0001750 00000003774 14541630232 024225 0 ustar pedro pedro /*
Drumstick MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef CONFIGURATIONDIALOGS_H
#define CONFIGURATIONDIALOGS_H
#include
#include
#include "macros.h"
/**
* @file configurationdialogs.h
* Functions providing configuration dialogs
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_WIDGETS_EXPORT
#else
#if defined(drumstick_widgets_EXPORTS)
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick {
/**
* @ingroup Widgets
* @brief Drumstick Widgets library
* MIDI related widgets and functions.
*/
namespace widgets {
bool DRUMSTICK_WIDGETS_EXPORT inputDriverIsConfigurable(const QString driver);
bool DRUMSTICK_WIDGETS_EXPORT outputDriverIsConfigurable(const QString driver);
bool DRUMSTICK_WIDGETS_EXPORT configureInputDriver(const QString driver, QWidget *parent = nullptr);
bool DRUMSTICK_WIDGETS_EXPORT configureOutputDriver(const QString driver, QWidget *parent = nullptr);
void DRUMSTICK_WIDGETS_EXPORT changeSoundFont(const QString driver,
const QString fileName,
QWidget *parent = nullptr);
QString DRUMSTICK_WIDGETS_EXPORT libraryVersion();
}} // namespace drumstick::widgets
#endif // CONFIGURATIONDIALOGS_H
drumstick-2.9.0/library/include/drumstick/alsaclient.h 0000644 0001750 0001750 00000024032 14541630232 022120 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_ALSACLIENT_H
#define DRUMSTICK_ALSACLIENT_H
#include
#include
#include
#include
#include
#include "macros.h"
#include "alsaport.h"
/**
* @file alsaclient.h
* Classes managing ALSA Sequencer clients
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
/**
* @brief Drumstick common
*/
namespace drumstick {
/**
* @ingroup ALSAGroup
* @brief Drumstick ALSA library wrapper
*/
namespace ALSA {
class MidiQueue;
class MidiClient;
class SequencerEvent;
class RemoveEvents;
/**
* @addtogroup ALSAClient ALSA Sequencer Clients
* @{
*
* @class ClientInfo
* Client information
*
* This class is used to retrieve, hold and set some data from
* sequencer clients, like the name or id.
*/
class DRUMSTICK_ALSA_EXPORT ClientInfo
{
friend class MidiClient;
public:
ClientInfo();
ClientInfo(const ClientInfo &other);
explicit ClientInfo(snd_seq_client_info_t *other);
ClientInfo(MidiClient* seq, int id);
virtual ~ClientInfo();
ClientInfo* clone();
ClientInfo& operator=(const ClientInfo &other);
int getSizeOfInfo() const;
int getClientId();
snd_seq_client_type_t getClientType();
QString getName();
bool getBroadcastFilter();
bool getErrorBounce();
int getNumPorts();
int getEventLost();
void setClient(int client);
void setName(QString name);
void setBroadcastFilter(bool val);
void setErrorBounce(bool val);
PortInfoList getPorts() const;
#if SND_LIB_VERSION > 0x010010
void addFilter(int eventType);
bool isFiltered(int eventType);
void clearFilter();
void removeFilter(int eventType);
#endif
protected:
void readPorts(MidiClient* seq);
void freePorts();
Q_DECL_DEPRECATED const unsigned char* getEventFilter();
Q_DECL_DEPRECATED void setEventFilter(unsigned char* filter);
private:
snd_seq_client_info_t* m_Info;
PortInfoList m_Ports;
};
/**
* List of sequencer client information
*/
typedef QList ClientInfoList;
/**
* System information
*
* This class is used to retrieve and hold some data about the
* whole sequencer subsystem.
*/
class DRUMSTICK_ALSA_EXPORT SystemInfo
{
friend class MidiClient;
public:
SystemInfo();
SystemInfo(const SystemInfo& other);
explicit SystemInfo(snd_seq_system_info_t* other);
explicit SystemInfo(MidiClient* seq);
virtual ~SystemInfo();
SystemInfo* clone();
SystemInfo& operator=(const SystemInfo& other);
int getSizeOfInfo() const;
int getMaxClients();
int getMaxPorts();
int getMaxQueues();
int getMaxChannels();
int getCurrentQueues();
int getCurrentClients();
private:
snd_seq_system_info_t* m_Info;
};
/**
* Sequencer Pool information
*
* This class is used to get and set the size of the input and output pool
* buffers for a sequencer client.
*/
class DRUMSTICK_ALSA_EXPORT PoolInfo
{
friend class MidiClient;
public:
PoolInfo();
PoolInfo(const PoolInfo& other);
explicit PoolInfo(snd_seq_client_pool_t* other);
explicit PoolInfo(MidiClient* seq);
virtual ~PoolInfo();
PoolInfo* clone();
PoolInfo& operator=(const PoolInfo& other);
int getSizeOfInfo() const;
int getClientId();
int getInputFree();
int getInputPool();
int getOutputFree();
int getOutputPool();
int getOutputRoom();
void setInputPool(int size);
void setOutputPool(int size);
void setOutputRoom(int size);
private:
snd_seq_client_pool_t* m_Info;
};
/**
* Sequencer events handler
*
* This abstract class is used to define an interface that other class can
* implement to receive sequencer events. It is one of the three methods of
* delivering events offered by this library.
*
* @see ALSAClient
*/
class DRUMSTICK_ALSA_EXPORT SequencerEventHandler
{
public:
/** Destructor */
virtual ~SequencerEventHandler() = default;
/**
* Callback function to be implemented by the derived class.
* It will be invoked by the client to deliver received events to the
* registered listener.
*
* @param ev A pointer to the received SequencerEvent
* @see MidiClient::setHandler(), MidiClient::startSequencerInput(),
* MidiClient::stopSequencerInput(), MidiClient::doEvents()
*/
virtual void handleSequencerEvent(SequencerEvent* ev) = 0;
};
/**
* Client management.
*
* This class represents an ALSA sequencer client
*/
class DRUMSTICK_ALSA_EXPORT MidiClient : public QObject
{
Q_OBJECT
public:
explicit MidiClient( QObject* parent = nullptr );
virtual ~MidiClient();
void open( const QString deviceName = "default",
const int openMode = SND_SEQ_OPEN_DUPLEX,
const bool blockMode = false );
void open( snd_config_t* conf,
const QString deviceName = "default",
const int openMode = SND_SEQ_OPEN_DUPLEX,
const bool blockMode = false );
void close();
void startSequencerInput();
void stopSequencerInput();
MidiPort* createPort();
MidiQueue* createQueue();
MidiQueue* createQueue(QString const& name);
MidiQueue* getQueue();
MidiQueue* useQueue(int queue_id);
MidiQueue* useQueue(const QString& name);
MidiQueue* useQueue(MidiQueue* queue);
void portAttach(MidiPort* port);
void portDetach(MidiPort* port);
void detachAllPorts();
void addEventFilter(int evtype);
void output(SequencerEvent* ev, bool async = false, int timeout = -1);
void outputDirect(SequencerEvent* ev, bool async = false, int timeout = -1);
void outputBuffer(SequencerEvent* ev);
void drainOutput(bool async = false, int timeout = -1);
void synchronizeOutput();
int getClientId();
snd_seq_type_t getSequencerType();
snd_seq_t* getHandle();
bool isOpened();
size_t getOutputBufferSize();
void setOutputBufferSize(size_t newSize);
size_t getInputBufferSize();
void setInputBufferSize(size_t newSize);
QString getDeviceName();
int getOpenMode();
bool getBlockMode();
void setBlockMode(bool newValue);
QString getClientName();
QString getClientName(const int clientId);
void setClientName(QString const& newName);
bool getBroadcastFilter();
void setBroadcastFilter(bool newValue);
bool getErrorBounce();
void setErrorBounce(bool newValue);
ClientInfo& getThisClientInfo();
void setThisClientInfo(const ClientInfo& val);
MidiPortList getMidiPorts() const;
ClientInfoList getAvailableClients();
PortInfoList getAvailableInputs();
PortInfoList getAvailableOutputs();
SystemInfo& getSystemInfo();
QList getAvailableQueues();
PoolInfo& getPoolInfo();
void setPoolInfo(const PoolInfo& info);
void setPoolInput(int size);
void setPoolOutput(int size);
void setPoolOutputRoom(int size);
void resetPoolInput();
void resetPoolOutput();
void dropInput();
void dropInputBuffer();
void dropOutput();
void dropOutputBuffer();
void removeEvents(const RemoveEvents* spec);
SequencerEvent* extractOutput();
int outputPending();
int inputPending(bool fetch);
int getQueueId(const QString& name);
void addListener(QObject* listener);
void removeListener(QObject* listener);
void setEventsEnabled(const bool bEnabled);
bool getEventsEnabled() const;
void setHandler(SequencerEventHandler* handler);
bool parseAddress( const QString& straddr, snd_seq_addr& result );
void setRealTimeInput(bool enabled);
bool realTimeInputEnabled();
Q_SIGNALS:
/** Signal emitted when an event is received
* @param ev pointer to the received event
*/
void eventReceived(drumstick::ALSA::SequencerEvent* ev);
protected:
void doEvents();
void applyClientInfo();
void readClients();
void freeClients();
void updateAvailablePorts();
PortInfoList filterPorts(unsigned int filter);
/* low level public functions */
const char * _getDeviceName();
int getPollDescriptorsCount(short events);
int pollDescriptors(struct pollfd *pfds, unsigned int space, short events);
unsigned short pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds);
/* mid level functions */
void _setClientName( const char *name );
int createSimplePort( const char *name,
unsigned int caps,
unsigned int type );
void deleteSimplePort( int port );
void connectFrom(int myport, int client, int port);
void connectTo(int myport, int client, int port);
void disconnectFrom(int myport, int client, int port);
void disconnectTo(int myport, int client, int port);
private:
class SequencerInputThread;
class MidiClientPrivate;
QScopedPointer d;
};
#if SND_LIB_VERSION > 0x010004
DRUMSTICK_ALSA_EXPORT QString getRuntimeALSALibraryVersion();
DRUMSTICK_ALSA_EXPORT int getRuntimeALSALibraryNumber();
#endif
DRUMSTICK_ALSA_EXPORT QString getRuntimeALSADriverVersion();
DRUMSTICK_ALSA_EXPORT int getRuntimeALSADriverNumber();
DRUMSTICK_ALSA_EXPORT QString getCompiledALSALibraryVersion();
DRUMSTICK_ALSA_EXPORT QString getDrumstickLibraryVersion();
/** @} */
}} /* namespace drumstick::ALSA */
#endif // DRUMSTICK_ALSACLIENT_H
drumstick-2.9.0/library/include/drumstick/alsaport.h 0000644 0001750 0001750 00000014575 14541630232 021641 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_ALSAPORT_H
#define DRUMSTICK_ALSAPORT_H
#include "subscription.h"
#include
namespace drumstick { namespace ALSA {
/**
* @file alsaport.h
* Classes managing ALSA Sequencer ports.
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
class MidiClient;
/**
* @addtogroup ALSAPort ALSA Sequencer Ports
* @{
*
* @class PortInfo
* Port information container
*/
class DRUMSTICK_ALSA_EXPORT PortInfo
{
friend class MidiPort;
friend class ClientInfo;
friend class MidiClient;
public:
PortInfo();
PortInfo(const PortInfo& other);
explicit PortInfo(snd_seq_port_info_t* other);
PortInfo(MidiClient* seq, const int client, const int port);
PortInfo(MidiClient* seq, const int port);
virtual ~PortInfo();
PortInfo* clone();
PortInfo& operator=(const PortInfo& other);
int getSizeOfInfo() const;
int getClient();
int getPort();
QString getClientName() const;
const snd_seq_addr_t* getAddr();
QString getName();
unsigned int getCapability();
unsigned int getType();
int getMidiChannels();
int getMidiVoices();
int getSynthVoices();
int getReadUse();
int getWriteUse();
int getPortSpecified();
void setClient(int client);
void setPort(int port);
void setAddr(const snd_seq_addr_t* addr);
void setName( QString const& name );
void setCapability(unsigned int capability);
void setType(unsigned int type);
void setMidiChannels(int channels);
void setMidiVoices(int voices);
void setSynthVoices(int voices);
void setPortSpecified(int val);
SubscribersList getReadSubscribers() const;
SubscribersList getWriteSubscribers() const;
bool getTimestamping();
bool getTimestampReal();
int getTimestampQueue();
void setTimestamping(bool value);
void setTimestampReal(bool value);
void setTimestampQueue(int queueId);
protected:
void readSubscribers(MidiClient* seq);
void freeSubscribers();
void setClientName(QString name);
private:
snd_seq_port_info_t* m_Info;
QString m_ClientName;
SubscribersList m_ReadSubscribers;
SubscribersList m_WriteSubscribers;
};
/**
* List of port information objects
*/
typedef QList PortInfoList;
/**
* Port management.
*
* This class represents an ALSA sequencer port.
*/
class DRUMSTICK_ALSA_EXPORT MidiPort : public QObject
{
Q_OBJECT
friend class MidiClient;
public:
explicit MidiPort( QObject* parent = nullptr );
virtual ~MidiPort();
void attach( MidiClient* seq );
void detach();
void subscribe( Subscription* subs );
void unsubscribe( Subscription* subs );
void unsubscribeAll();
void unsubscribeTo( QString const& name );
void unsubscribeTo( PortInfo* port );
void unsubscribeTo( const snd_seq_addr_t* addr );
void unsubscribeFrom( QString const& name );
void unsubscribeFrom( PortInfo* port );
void unsubscribeFrom( const snd_seq_addr_t* addr );
void subscribeTo( PortInfo* port);
void subscribeTo( int client, int port );
void subscribeTo( QString const& name );
void subscribeFrom( PortInfo* port );
void subscribeFrom( int client, int port );
void subscribeFrom( QString const& name );
void subscribeFromAnnounce();
void updateSubscribers();
SubscriptionsList getSubscriptions() const;
PortInfoList getReadSubscribers();
PortInfoList getWriteSubscribers();
void updateConnectionsTo(const PortInfoList& desired);
void updateConnectionsFrom(const PortInfoList& desired);
static bool containsAddress(const snd_seq_addr_t* addr, const PortInfoList& lst);
void applyPortInfo();
QString getPortName();
void setPortName( QString const& newName);
int getPortId();
unsigned int getCapability();
void setCapability( unsigned int newValue);
unsigned int getPortType();
void setPortType( unsigned int newValue);
int getMidiChannels();
void setMidiChannels(int newValue);
int getMidiVoices();
void setMidiVoices(int newValue);
int getSynthVoices();
void setSynthVoices(int newValue);
bool getTimestamping();
bool getTimestampReal();
int getTimestampQueue();
void setTimestamping(bool value);
void setTimestampReal(bool value);
void setTimestampQueue(int queueId);
Q_SIGNALS:
/**
* Signal emitted when an internal subscription is done.
* @param port MIDI port object pointer
* @param subs Subscription object pointer
*/
void subscribed(drumstick::ALSA::MidiPort* port, drumstick::ALSA::Subscription* subs);
/**
* Signal emitted when the MidiClient has changed
* @param port MIDI port object pinter
* @param seq MidiClient object pointer
*/
void midiClientChanged(drumstick::ALSA::MidiPort* port, drumstick::ALSA::MidiClient* seq);
/**
* Signal emitted when the port is attached to a MidiClient
* @param port MIDI port object pointer
*/
void attached(drumstick::ALSA::MidiPort* port);
/**
* Signal emitted when the port is detached from a MidiClient
* @param port MIDI port object pointer
*/
void detached(drumstick::ALSA::MidiPort* port);
protected:
PortInfo* getPortInfo();
void freeSubscriptions();
void setMidiClient( MidiClient* seq );
private:
MidiClient* m_MidiClient;
PortInfo m_Info;
bool m_Attached;
SubscriptionsList m_Subscriptions;
};
/**
* List of Ports instances.
*/
typedef QList MidiPortList;
/** @} */
}} /* namespace drumstick::ALSA */
#endif //DRUMSTICK_ALSAPORT_H
drumstick-2.9.0/library/include/drumstick/alsatimer.h 0000644 0001750 0001750 00000022536 14541630232 021771 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_ALSATIMER_H
#define DRUMSTICK_ALSATIMER_H
extern "C" {
#include
}
#include
#include
#include
#include
#include
#include "macros.h"
namespace drumstick { namespace ALSA {
/**
* @file alsatimer.h
* Classes managing ALSA Timers
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
class TimerQuery;
class TimerId;
class TimerGlobalInfo;
/**
* @addtogroup ALSATimer ALSA Timers
* @{
*
* @class TimerInfo
* ALSA Timer information container.
*
* This class is used to hold properties about ALSA Timers.
*/
class DRUMSTICK_ALSA_EXPORT TimerInfo
{
friend class Timer;
public:
TimerInfo();
TimerInfo(const TimerInfo& other);
explicit TimerInfo(const snd_timer_info_t* other);
virtual ~TimerInfo();
TimerInfo* clone();
TimerInfo& operator=(const TimerInfo& other);
int getSizeOfInfo() const;
bool isSlave();
int getCard();
QString getId();
QString getName();
long getResolution();
long getFrequency();
protected:
Q_DECL_DEPRECATED long getTicks();
private:
snd_timer_info_t *m_Info;
};
/**
* ALSA Timer identifier container.
*
* This class provides an unique identifier for a Timer.
*/
class DRUMSTICK_ALSA_EXPORT TimerId
{
friend class TimerQuery;
friend class TimerGlobalInfo;
friend class QueueTimer;
public:
TimerId();
TimerId(const TimerId& other);
explicit TimerId(const snd_timer_id_t *other);
TimerId(int cls, int scls, int card, int dev, int sdev);
virtual ~TimerId();
TimerId* clone();
TimerId& operator=(const TimerId& other);
int getSizeOfInfo() const;
void setClass(int devclass);
int getClass();
void setSlaveClass(int devsclass);
int getSlaveClass();
void setCard(int card);
int getCard();
void setDevice(int device);
int getDevice();
void setSubdevice(int subdevice);
int getSubdevice();
private:
snd_timer_id_t *m_Info;
};
/**
* List of timer identifiers
*/
typedef QList TimerIdList;
/**
* Global timer information container.
*
* This class provides global timer parameters.
*/
class DRUMSTICK_ALSA_EXPORT TimerGlobalInfo
{
friend class TimerQuery;
public:
TimerGlobalInfo();
TimerGlobalInfo(const TimerGlobalInfo& other);
explicit TimerGlobalInfo(const snd_timer_ginfo_t* other);
virtual ~TimerGlobalInfo();
TimerGlobalInfo* clone();
TimerGlobalInfo& operator=(const TimerGlobalInfo& other);
int getSizeOfInfo() const;
void setTimerId(const TimerId& tid);
TimerId& getTimerId();
unsigned int getFlags();
int getCard();
QString getId();
QString getName();
unsigned long getResolution();
unsigned long getMinResolution();
unsigned long getMaxResolution();
unsigned int getClients();
private:
snd_timer_ginfo_t* m_Info;
TimerId m_Id;
};
/**
* ALSA Timer inquiry helper.
*
* This class provides a mechanism to enumerate the available system timers.
*/
class DRUMSTICK_ALSA_EXPORT TimerQuery
{
public:
TimerQuery(const QString& deviceName, int openMode);
TimerQuery(const QString& deviceName, int openMode, snd_config_t* conf);
virtual ~TimerQuery();
/**
* Gets the list of available timers
* @return List of TimerId objects
*/
TimerIdList getTimers() const { return m_timers; }
TimerGlobalInfo& getGlobalInfo();
void setGlobalParams(snd_timer_gparams_t* params);
void getGlobalParams(snd_timer_gparams_t* params);
void getGlobalStatus(snd_timer_gstatus_t* status);
protected:
void readTimers();
void freeTimers();
private:
snd_timer_query_t *m_Info;
TimerIdList m_timers;
TimerGlobalInfo m_GlobalInfo;
};
/**
* ALSA Timer parameters container.
*
* This class provides several parameters about a Timer.
*/
class DRUMSTICK_ALSA_EXPORT TimerParams
{
friend class Timer;
public:
TimerParams();
TimerParams(const TimerParams& other);
explicit TimerParams(const snd_timer_params_t* other);
virtual ~TimerParams();
TimerParams* clone();
TimerParams& operator=(const TimerParams& other);
int getSizeOfInfo() const;
void setAutoStart(bool auto_start);
bool getAutoStart();
void setExclusive(bool exclusive);
bool getExclusive();
void setEarlyEvent(bool early_event);
bool getEarlyEvent();
void setTicks(long ticks);
long getTicks();
void setQueueSize(long queue_size);
long getQueueSize();
void setFilter(unsigned int filter);
unsigned int getFilter();
private:
snd_timer_params_t* m_Info;
};
/**
* ALSA Timer status container.
*
* This class provides some status information about a Timer.
*/
class DRUMSTICK_ALSA_EXPORT TimerStatus
{
friend class Timer;
public:
TimerStatus();
TimerStatus(const TimerStatus& other);
explicit TimerStatus(const snd_timer_status_t* other);
virtual ~TimerStatus();
TimerStatus* clone();
TimerStatus& operator=(const TimerStatus& other);
int getSizeOfInfo() const;
snd_htimestamp_t getTimestamp();
long getResolution();
long getLost();
long getOverrun();
long getQueue();
private:
snd_timer_status_t* m_Info;
};
/**
* ALSA Timer events handler.
*
* This abstract class is used to define an interface that other class can
* implement to receive timer events.
*/
class DRUMSTICK_ALSA_EXPORT TimerEventHandler
{
public:
/** Destructor */
virtual ~TimerEventHandler() = default;
/**
* Timer event handler. This method is called when the timer expires.
* @param ticks The time in ticks.
* @param msecs The time in milliseconds.
*/
virtual void handleTimerEvent(int ticks, int msecs) = 0;
};
/**
* ALSA Timer management.
*
* This class represents an ALSA timer object.
*/
class DRUMSTICK_ALSA_EXPORT Timer : public QObject
{
Q_OBJECT
private:
/**
* This class manages timer events input from ALSA
*/
class TimerInputThread : public QThread
{
public:
/** Constructor */
TimerInputThread(Timer* t, int timeout)
: QThread(),
m_timer(t),
m_Wait(timeout),
m_Stopped(false) {}
/** Destructor */
virtual ~TimerInputThread() = default;
void run() override;
bool stopped();
void stop();
private:
Timer* m_timer;
int m_Wait;
bool m_Stopped;
QReadWriteLock m_mutex;
};
public:
Timer(int cls, int scls, int card, int dev, int sdev, int openMode, QObject* parent = nullptr);
Timer(const QString& deviceName, int openMode, QObject* parent = nullptr);
Timer(const QString& deviceName, int openMode, snd_config_t* config, QObject* parent = nullptr);
Timer(TimerId& id, int openMode, QObject* parent = nullptr);
virtual ~Timer();
static TimerId bestGlobalTimerId();
static Timer* bestGlobalTimer(int openMode, QObject* parent = nullptr);
/**
* Gets the ALSA timer object.
* @return ALSA timer object pointer.
*/
snd_timer_t* getHandle() { return m_Info; }
TimerInfo& getTimerInfo();
TimerStatus& getTimerStatus();
void setTimerParams(const TimerParams& params);
void start();
void stop();
void continueRunning();
void addAsyncTimerHandler(snd_async_callback_t callback, void *private_data);
int getPollDescriptorsCount();
void pollDescriptors(struct pollfd *pfds, unsigned int space);
void pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
ssize_t read(void *buffer, size_t size);
snd_timer_t* getTimerHandle();
/**
* Sets an event handler providing a method to be called when a timer expires.
* @param h A TimerEventHandler instance.
*/
void setHandler(TimerEventHandler* h) { m_handler = h; }
void startEvents();
void stopEvents();
protected:
void doEvents();
Q_SIGNALS:
/**
* This signal is emitted when the timer has expired, if there is not an
* event hander installed.
*
* @param ticks The time in ticks.
* @param msecs The time in milliseconds.
*/
void timerExpired(int ticks, int msecs);
private:
snd_timer_t *m_Info;
snd_async_handler_t *m_asyncHandler;
TimerEventHandler* m_handler;
QPointer m_thread;
TimerInfo m_TimerInfo;
TimerStatus m_TimerStatus;
QString m_deviceName;
snd_htimestamp_t m_last_time;
};
/** @} */
}} /* namespace drumstick::ALSA */
#endif /* DRUMSTICK_ALSATIMER_H */
drumstick-2.9.0/library/include/drumstick/pianokeybd.h 0000644 0001750 0001750 00000027715 14541630232 022141 0 ustar pedro pedro /*
Virtual Piano Widget for Qt
Copyright (C) 2008-2023, Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef PIANOKEYBD_H
#define PIANOKEYBD_H
#include
#include
#include
#include "macros.h"
#include "pianopalette.h"
/**
* @file pianokeybd.h
* Piano Keyboard Widget
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_WIDGETS_EXPORT
#else
#if defined(drumstick_widgets_EXPORTS)
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick { namespace widgets {
Q_NAMESPACE
/**
* @addtogroup Widgets
* @{
*
* @class RawKbdHandler
* @brief The RawKbdHandler class callbacks
*
* RawKbdHandler provides callbacks for low level computer keyboard events
*/
class RawKbdHandler {
public:
virtual ~RawKbdHandler() = default;
/**
* @brief handleKeyPressed handles low level computer keyboard press events
* @param keycode The low level key code pressed
* @return whether the event has been processed or not
*/
virtual bool handleKeyPressed(int keycode) = 0;
/**
* @brief handleKeyReleased handles low level computer keyboard reelase events
* @param keycode The low level key code released
* @return whether the event has been processed or not
*/
virtual bool handleKeyReleased(int keycode) = 0;
};
/**
* @brief The PianoHandler class callbacks
*
* This class provides handler methods for note events. This class must be
* inherited and implemented by a program using also PianoKeybd to receive the
* note events generated from a computer keyboard, mouse or touch events. It is
* provided using the method @ref PianoKeybd::setPianoHandler() and can be retrieved
* using @ref PianoKeybd::getPianoHandler(). This mechanism is an option alternative
* to proces signals @ref PianoKeybd::noteOn() and @ref PianoKeybd::noteOff() .
*/
class PianoHandler
{
public:
virtual ~PianoHandler() = default;
/**
* @brief noteOn handles MIDI note on events
* @param note MIDI note number
* @param vel MIDI velocity
*/
virtual void noteOn( const int note, const int vel ) = 0;
/**
* @brief noteOff handles MIDI note off events
* @param note MIDI note number
* @param vel MIDI velocity
*/
virtual void noteOff( const int note, const int vel ) = 0;
};
/**
* @brief KeyboardMap
*
* KeyboardMap represents a mapping definition to translate from
* computer keyboard keys and MIDI notes, either for alphanumeric
* or low level (raw) events.
*/
typedef QHash KeyboardMap;
extern DRUMSTICK_WIDGETS_EXPORT KeyboardMap g_DefaultKeyMap; ///< Global Key Map Variable
extern DRUMSTICK_WIDGETS_EXPORT KeyboardMap g_DefaultRawKeyMap; ///< Global Raw Key Map Variable
const int DEFAULTSTARTINGKEY = 9; ///< Default starting key (A)
const int DEFAULTBASEOCTAVE = 1; ///< Default base octave
const int DEFAULTNUMBEROFKEYS = 88; ///< Default number of piano keys
/**
* @brief Labels Visibility
*/
enum LabelVisibility {
ShowNever, ///< Don't show note names
ShowMinimum, ///< Show only note C names
ShowActivated, ///< Show names when notes are activated
ShowAlways ///< Show always note names
};
Q_ENUM_NS(LabelVisibility)
/**
* @brief Labels for Alterations
*/
enum LabelAlteration {
ShowSharps, ///< Show sharps on black keys
ShowFlats, ///< Show flats on black keys
ShowNothing ///< Do not show names on black keys
};
Q_ENUM_NS(LabelAlteration)
/**
* @brief Labels Orientation
*/
enum LabelOrientation {
HorizontalOrientation, ///< Show horizontal names
VerticalOrientation, ///< Show vertical names
AutomaticOrientation ///< Show horizonal or vertical names depending on the size
};
Q_ENUM_NS(LabelOrientation)
/**
* @brief Labels Naming
*/
enum LabelNaming {
StandardNames, ///< Show standard names
CustomNamesWithSharps, ///< Show custom names with sharps
CustomNamesWithFlats ///< Show custom names with flats
};
Q_ENUM_NS(LabelNaming)
/**
* @brief Labels Central Octave
*/
enum LabelCentralOctave {
OctaveNothing = -1, ///< Don't show octave numbers
OctaveC3, ///< Central C, MIDI note #60 is C3
OctaveC4, ///< Central C, MIDI note #60 is C4
OctaveC5 ///< Central C, MIDI note #60 is C5
};
Q_ENUM_NS(LabelCentralOctave)
/**
* @brief The PianoKeybd class
*
* This class is a widget providing the look and behavior of a musical piano keyboard.
* It is implemented as a QGraphicsView displaying the contents of a QGraphicsScene (PianoScene).
*/
class DRUMSTICK_WIDGETS_EXPORT PianoKeybd : public QGraphicsView, public RawKbdHandler
{
Q_OBJECT
Q_PROPERTY( int baseOctave READ baseOctave WRITE setBaseOctave )
Q_PROPERTY( int numKeys READ numKeys WRITE setNumKeys )
Q_PROPERTY( int rotation READ getRotation WRITE setRotation )
Q_PROPERTY( QColor keyPressedColor READ getKeyPressedColor WRITE setKeyPressedColor )
Q_PROPERTY( drumstick::widgets::LabelVisibility showLabels READ showLabels WRITE setShowLabels )
Q_PROPERTY( drumstick::widgets::LabelAlteration alterations READ labelAlterations WRITE setLabelAlterations )
Q_PROPERTY( drumstick::widgets::LabelOrientation labelOrientation READ labelOrientation WRITE setLabelOrientation )
Q_PROPERTY( drumstick::widgets::LabelCentralOctave labelOctave READ labelOctave WRITE setLabelOctave )
Q_PROPERTY( int transpose READ getTranspose WRITE setTranspose )
Q_PROPERTY( int startKey READ startKey WRITE setStartKey )
Q_PROPERTY( QFont labelFont READ font WRITE setFont )
#ifndef Q_MOC_RUN
Q_CLASSINFO("Author", "Pedro Lopez-Cabanillas ")
Q_CLASSINFO("URL", "https://sourceforge.net/projects/drumstick")
Q_CLASSINFO("Version", QT_STRINGIFY(VERSION))
#endif
public:
explicit PianoKeybd(QWidget *parent = nullptr);
PianoKeybd(const int baseOctave, const int numKeys, const int startKey, QWidget *parent = nullptr);
virtual ~PianoKeybd();
void setFont(const QFont &font);
PianoHandler* getPianoHandler() const;
void setPianoHandler(PianoHandler* handler);
PianoPalette getHighlightPalette() const;
void setHighlightPalette(const PianoPalette& p );
PianoPalette getBackgroundPalette() const;
void setBackgroundPalette(const PianoPalette& p );
PianoPalette getForegroundPalette() const;
void setForegroundPalette(const PianoPalette& p );
bool showColorScale() const;
void setShowColorScale(const bool show);
void useCustomNoteNames(const QStringList& names);
void useStandardNoteNames();
QStringList customNoteNames() const;
QStringList standardNoteNames() const;
void retranslate();
int baseOctave() const;
void setBaseOctave(const int baseOctave);
int numKeys() const;
int startKey() const;
void setNumKeys(const int numKeys, const int startKey = DEFAULTSTARTINGKEY);
int getRotation() const;
void setRotation(int r);
QColor getKeyPressedColor() const;
void setKeyPressedColor(const QColor& c);
void resetKeyPressedColor();
LabelVisibility showLabels() const;
void setShowLabels(const LabelVisibility show);
LabelAlteration labelAlterations() const;
void setLabelAlterations(const LabelAlteration use);
LabelOrientation labelOrientation() const;
void setLabelOrientation(const LabelOrientation orientation);
LabelCentralOctave labelOctave() const;
void setLabelOctave(const LabelCentralOctave octave);
int getTranspose() const;
void setTranspose(int t);
int getChannel() const;
void setChannel(const int c);
int getVelocity() const;
void setVelocity(const int v);
bool isKeyboardEnabled() const;
void setKeyboardEnabled( const bool enable );
bool isMouseEnabled() const;
void setMouseEnabled( const bool enable );
bool isTouchEnabled() const;
void setTouchEnabled( const bool enable );
bool velocityTint() const ;
void setVelocityTint( const bool enable );
void allKeysOff();
QSize sizeHint() const override;
void setKeyboardMap(KeyboardMap* m);
KeyboardMap* getKeyboardMap();
void resetKeyboardMap();
void setRawKeyboardMap(KeyboardMap* m);
KeyboardMap* getRawKeyboardMap();
void resetRawKeyboardMap();
bool getRawKeyboardMode() const;
void setRawKeyboardMode(const bool b);
void showNoteOn( const int note, QColor color, int vel = -1 );
void showNoteOn( const int note, int vel = -1 );
void showNoteOff( const int note, int vel = -1 );
// RawKbdHandler methods
bool handleKeyPressed(int keycode) override;
bool handleKeyReleased(int keycode) override;
void setKeyPicture(const bool natural, const QPixmap& pix);
QPixmap getKeyPicture(const bool natural);
void setUseKeyPictures(const bool enable);
bool getUseKeyPictures() const;
void setUsingNativeFilter(const bool newState);
bool isUsingNativeFilter() const;
void setOctaveSubscript(const bool enable);
bool octaveSubscript() const;
void setStartKey(const int startKey);
Q_SIGNALS:
/**
* This signal is emitted for each Note On MIDI event created using
* the computer keyboard, mouse or touch screen. It is not emitted if
* a PianoHandler has been assigned using setPianoHandler().
* @param midiNote the MIDI note number
* @param vel the MIDI velocity
*/
void noteOn( int midiNote, int vel );
/**
* This signal is emitted for each Note Off MIDI event created using
* the computer keyboard, mouse or touch screen. It is not emitted if
* a PianoHandler has been assigned using setPianoHandler().
* @param midiNote the MIDI note number
* @param vel the MIDI velocity
*/
void noteOff( int midiNote, int vel );
/**
* signalName is emitted for each note created, and contains a string
* with the MIDI note number and the note name for each note on event.
* @param name the MIDI note number and name
*/
void signalName( const QString& name );
protected:
void initialize();
void initDefaultMap();
void initScene(int base, int num, int ini, const QColor& c = QColor());
void resizeEvent(QResizeEvent *event) override;
bool viewportEvent(QEvent *ev) override;
private:
class PianoKeybdPrivate;
QScopedPointer d;
};
/** @} */
}} // namespace drumstick::widgets
#endif // PIANOKEYBD_H
drumstick-2.9.0/library/include/drumstick/playthread.h 0000644 0001750 0001750 00000007613 14541630232 022144 0 ustar pedro pedro /*
MIDI Sequencer C++ library
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_PLAYTHREAD_H
#define DRUMSTICK_PLAYTHREAD_H
#include "alsaevent.h"
#include
#include
namespace drumstick { namespace ALSA {
/**
* @file playthread.h
* Sequencer output thread
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_ALSA_EXPORT
#else
#if defined(drumstick_alsa_EXPORTS)
#define DRUMSTICK_ALSA_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_ALSA_EXPORT Q_DECL_IMPORT
#endif
#endif
class MidiClient;
class MidiQueue;
/**
* @addtogroup PlayThread ALSA Sequencer Output
* @{
*
* @class SequencerOutputThread
* Sequence player auxiliary class
*
* This class is used to implement an asynchronous sequence player using
* ALSA sequencer scheduling
*
* Examples: guiplayer.cpp and playsmf.cpp
*/
class DRUMSTICK_ALSA_EXPORT SequencerOutputThread : public QThread
{
Q_OBJECT
public:
SequencerOutputThread(MidiClient *seq, int portId);
virtual void run() override;
/**
* Gets the initial position in ticks of the sequence. The
* default value zero means starting from the beginning.
* @return Initial position (ticks)
*/
virtual unsigned int getInitialPosition() { return 0; }
/**
* Gets the echo event resolution in ticks. This is the time
* between echo events interleaved with the MIDI sequence. The default
* value zero means that no echo events are sent at all.
* @return Echo resolution (ticks)
*/
virtual unsigned int getEchoResolution() { return 0; }
/**
* Check if there is one more event in the sequence.
* This is a pure virtual method that must be overridden in the derived
* class.
* @return True if the sequence has another event.
*/
virtual bool hasNext() = 0;
/**
* Gets the next event in the sequence.
* This is a pure virtual function that must be overridden in the derived
* class.
* @return Pointer to the next SequencerEvent to be played.
*/
virtual SequencerEvent* nextEvent() = 0;
/**
* Stops playing the current sequence.
*/
virtual void stop();
Q_SIGNALS:
/**
* Signal emitted when the sequence play-back has finished.
*/
void playbackFinished();
/**
* Signal emitted when the play-back has stopped.
*/
void playbackStopped();
public Q_SLOTS:
void start( QThread::Priority priority = InheritPriority );
protected:
virtual void sendEchoEvent(int tick);
virtual void sendSongEvent(SequencerEvent* ev);
virtual void drainOutput();
virtual void syncOutput();
virtual bool stopRequested();
MidiClient *m_MidiClient; /**< MidiClient instance pointer */
MidiQueue *m_Queue; /**< MidiQueue instance pointer */
int m_PortId; /**< MidiPort numeric identifier */
bool m_Stopped; /**< Stopped status */
int m_QueueId; /**< MidiQueue numeric identifier */
int m_npfds; /**< Number of pollfd pointers */
pollfd* m_pfds; /**< Array of pollfd pointers */
QReadWriteLock m_mutex; /**< Mutex object used for synchronization */
};
/** @} */
}} /* namespace drumstick::ALSA */
#endif /*DRUMSTICK_PLAYTHREAD_H*/
drumstick-2.9.0/library/include/drumstick/qsmf.h 0000644 0001750 0001750 00000027766 14541630232 020770 0 ustar pedro pedro /*
Standard MIDI File component
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
Based on midifile.c by Tim Thompson, M.Czeiszperger and Greg Lee
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef DRUMSTICK_QSMF_H
#define DRUMSTICK_QSMF_H
#include "macros.h"
#include
#include
class QTextCodec;
class QDataStream;
/**
* @file qsmf.h
* Standard MIDI Files Input/Output
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_FILE_EXPORT
#else
#if defined(drumstick_file_EXPORTS)
#define DRUMSTICK_FILE_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_FILE_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick {
/**
* @ingroup File
* @brief Drumstick File library
*/
namespace File {
/**
* @addtogroup SMF Standard MIDI Files Management (I/O)
* @{
*/
const quint32 MThd = 0x4d546864; /**< SMF Header prefix */
const quint32 MTrk = 0x4d54726b; /**< SMF Track prefix */
/* Standard MIDI Files meta event definitions */
const quint8 meta_event = 0xff; /**< SMF Meta Event prefix */
const quint8 sequence_number = 0x00; /**< SMF Sequence number */
const quint8 text_event = 0x01; /**< SMF Text event */
const quint8 copyright_notice = 0x02; /**< SMF Copyright notice */
const quint8 sequence_name = 0x03; /**< SMF Sequence name */
const quint8 instrument_name = 0x04; /**< SMF Instrument name */
const quint8 lyric = 0x05; /**< SMF Lyric */
const quint8 marker = 0x06; /**< SMF Marker */
const quint8 cue_point = 0x07; /**< SMF Cue point */
const quint8 forced_channel = 0x20; /**< SMF Forced MIDI channel */
const quint8 forced_port = 0x21; /**< SMF Forced MIDI port */
const quint8 end_of_track = 0x2f; /**< SMF End of track */
const quint8 set_tempo = 0x51; /**< SMF Tempo change */
const quint8 smpte_offset = 0x54; /**< SMF SMPTE offset */
const quint8 time_signature = 0x58; /**< SMF Time signature */
const quint8 key_signature = 0x59; /**< SMF Key signature */
const quint8 sequencer_specific = 0x7f; /**< SMF Sequencer specific */
/* MIDI status commands most significant bit is 1 */
const quint8 note_off = 0x80; /**< MIDI event Note Off */
const quint8 note_on = 0x90; /**< MIDI event Note On */
const quint8 poly_aftertouch = 0xa0; /**< MIDI event Polyphonic pressure */
const quint8 control_change = 0xb0; /**< MIDI event Control change */
const quint8 program_chng = 0xc0; /**< MIDI event Program change */
const quint8 channel_aftertouch = 0xd0; /**< MIDI event Channel after-touch */
const quint8 pitch_wheel = 0xe0; /**< MIDI event Bender */
const quint8 system_exclusive = 0xf0; /**< MIDI event System Exclusive begin */
const quint8 end_of_sysex = 0xf7; /**< MIDI event System Exclusive end */
const quint8 midi_command_mask = 0xf0; /**< Mask to extract the command from the status byte */
const quint8 midi_channel_mask = 0x0f; /**< Mask to extract the channel from the status byte */
const quint8 major_mode = 0; /**< Major mode scale */
const quint8 minor_mode = 1; /**< Minor mode scale */
/**
* Standard MIDI Files input/output
*
* This class is used to parse and encode Standard MIDI Files (SMF)
*/
class DRUMSTICK_FILE_EXPORT QSmf : public QObject
{
Q_OBJECT
public:
explicit QSmf(QObject * parent = nullptr);
virtual ~QSmf();
void readFromStream(QDataStream *stream);
void readFromFile(const QString& fileName);
void writeToStream(QDataStream *stream);
void writeToFile(const QString& fileName);
void writeMetaEvent(long deltaTime, int type, const QByteArray& data);
void writeMetaEvent(long deltaTime, int type, const QString& data);
void writeMetaEvent(long deltaTime, int type, int data);
void writeMetaEvent(long deltaTime, int type);
void writeMidiEvent(long deltaTime, int type, int chan, int b1);
void writeMidiEvent(long deltaTime, int type, int chan, int b1, int b2);
void writeMidiEvent(long deltaTime, int type, int chan, const QByteArray& data);
void writeMidiEvent(long deltaTime, int type, long len, char* data);
void writeTempo(long deltaTime, long tempo);
void writeBpmTempo(long deltaTime, int tempo);
void writeTimeSignature(long deltaTime, int num, int den, int cc, int bb);
void writeKeySignature(long deltaTime, int tone, int mode);
void writeSequenceNumber(long deltaTime, int seqnum);
long getCurrentTime();
long getCurrentTempo();
long getRealTime();
long getFilePos();
int getDivision();
void setDivision(int division);
int getTracks();
void setTracks(int tracks);
int getFileFormat();
void setFileFormat(int fileFormat);
Q_DECL_DEPRECATED QTextCodec* getTextCodec();
Q_DECL_DEPRECATED void setTextCodec(QTextCodec *codec);
Q_SIGNALS:
/**
* Emitted for a SMF read or write error
* @param errorStr Error string
*/
void signalSMFError(const QString& errorStr);
/**
* Emitted after reading a SMF header
* @param format SMF format (0/1)
* @param ntrks Number pof tracks
* @param division Division (resolution in ticks per quarter note)
*/
void signalSMFHeader(int format, int ntrks, int division);
/**
* Emitted after reading a Note On message
* @param chan MIDI Channel
* @param pitch MIDI Note
* @param vol Velocity
*/
void signalSMFNoteOn(int chan, int pitch, int vol);
/**
* Emitted after reading a Note Off message
* @param chan MIDI Channel
* @param pitch MIDI Note
* @param vol Velocity
*/
void signalSMFNoteOff(int chan, int pitch, int vol);
/**
* Emitted after reading a Polyphonic Aftertouch message
* @param chan MIDI Channel
* @param pitch MIDI Note
* @param press Pressure amount
*/
void signalSMFKeyPress(int chan, int pitch, int press);
/**
* Emitted after reading a Control Change message
* @param chan MIDI Channel
* @param ctl MIDI Controller
* @param value Control value
*/
void signalSMFCtlChange(int chan, int ctl, int value);
/**
* Emitted after reading a Bender message
* @param chan MIDI Channel
* @param value Bender value
*/
void signalSMFPitchBend(int chan, int value);
/**
* Emitted after reading a Program change message
* @param chan MIDI Channel
* @param patch Program number
*/
void signalSMFProgram(int chan, int patch);
/**
* Emitted after reading a Channel Aftertouch message
* @param chan MIDI Channel
* @param press Pressure amount
*/
void signalSMFChanPress(int chan, int press);
/**
* Emitted after reading a System Exclusive message
* @param data Sysex bytes
*/
void signalSMFSysex(const QByteArray& data);
/**
* Emitted after reading a Sequencer specific message
* @param data Message data
*/
void signalSMFSeqSpecific(const QByteArray& data);
/**
* Emitted after reading an unregistered SMF Meta message
* @param typ Message type
* @param data Message data
* @since 0.2.0
*/
void signalSMFMetaUnregistered(int typ, const QByteArray& data);
/**
* Emitted after reading any SMF Meta message
* @param typ Message type
* @param data Message data
*/
void signalSMFMetaMisc(int typ, const QByteArray& data);
/**
* Emitted after reading a Sequence number message
* @param seq Sequence number
*/
void signalSMFSequenceNum(int seq);
/**
* Emitted after reading a Forced channel message
* @param channel MIDI Channel
*/
void signalSMFforcedChannel(int channel);
/**
* Emitted after reading a Forced port message
* @param port Port number
*/
void signalSMFforcedPort(int port);
/**
* Emitted after reading a SMF text message
* @param typ Text type
* @param data Text data
* @deprecated because the class QTextCodec was removed from QtCore since Qt6.
* use signalSMFText2() instead.
*/
Q_DECL_DEPRECATED void signalSMFText(int typ, const QString& data);
/**
* Emitted after reading a SMF text message
* @param typ Text type
* @param data Text data
*/
void signalSMFText2(int typ, const QByteArray& data);
/**
* Emitted after reading a SMPT offset message
* @param b0 Hours
* @param b1 Minutes
* @param b2 Seconds
* @param b3 Frames
* @param b4 Fractional frames
*/
void signalSMFSmpte(int b0, int b1, int b2, int b3, int b4);
/**
* Emitted after reading a SMF Time signature message
* @param b0 Numerator
* @param b1 Denominator (exponent in a power of two)
* @param b2 Number of MIDI clocks per metronome click
* @param b3 Number of notated 32nd notes per 24 MIDI clocks
*/
void signalSMFTimeSig(int b0, int b1, int b2, int b3);
/**
* Emitted after reading a SMF Key Signature smessage
* @param b0 Number of alterations (negative=flats, positive=sharps)
* @param b1 Scale Mode (0=major, 1=minor)
*/
void signalSMFKeySig(int b0, int b1);
/**
* Emitted after reading a Tempo Change message
* @param tempo Microseconds per quarter note
*/
void signalSMFTempo(int tempo);
/**
* Emitted after reading a End-Of-Track message
*/
void signalSMFendOfTrack();
/**
* Emitted after reading a track prefix
*/
void signalSMFTrackStart();
/**
* Emitted after a track has finished
*/
void signalSMFTrackEnd();
/**
* Emitted to request the user to prepare the tempo track.
*
* The signal handler should not call the writeTempo() or writeBpmTempo()
* methods directly, but instead it should fill the Conductor track with
* tempo and other SMF meta events like key and time signatures to be written
* later, at the signalSMFWriteTrack() handler.
*
* The Conductor track is the first track in a format 1 SMF.
*/
void signalSMFWriteTempoTrack();
/**
* Emitted to request the user to write a track.
* @param track Track number
*/
void signalSMFWriteTrack(int track);
private:
/**
* Tempo change within a SMF or sequence
*/
struct QSmfRecTempo
{
quint64 tempo;
quint64 time;
};
class QSmfPrivate;
QScopedPointer d;
void SMFRead();
void SMFWrite();
quint8 getByte();
void putByte(quint8 value);
void readHeader();
void readTrack();
quint16 to16bit(quint8 c1, quint8 c2);
quint32 to32bit(quint8 c1, quint8 c2, quint8 c3, quint8 c4);
quint16 read16bit();
quint32 read32bit();
void write16bit(quint16 data);
void write32bit(quint32 data);
void writeVarLen(quint64 value);
double ticksToSecs(quint64 ticks, quint16 division, quint64 tempo);
long readVarLen();
void readExpected(const QString& s);
void addTempo(quint64 tempo, quint64 time);
quint64 findTempo();
void SMFError(const QString& s);
void channelMessage(quint8 status, quint8 c1, quint8 c2);
void msgInit();
void msgAdd(quint8 b);
void metaEvent(quint8 b);
void sysEx();
void badByte(quint8 b, int p);
quint8 lowerByte(quint16 x);
quint8 upperByte(quint16 x);
bool endOfSmf();
void writeHeaderChunk(int format, int ntracks, int division);
void writeTrackChunk(int track);
};
QString DRUMSTICK_FILE_EXPORT drumstickLibraryVersion();
/** @} */
}} /* namespace drumstick::File */
#endif /* DRUMSTICK_QSMF_H */
drumstick-2.9.0/library/include/drumstick/rmid.h 0000644 0001750 0001750 00000012661 14541630232 020741 0 ustar pedro pedro /*
Standard RIFF MIDI Component
Copyright (C) 2006-2023, Pedro Lopez-Cabanillas
This library 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 3 of the License, or
(at your option) any later version.
This library 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, see .
*/
#ifndef RMIDI_H
#define RMIDI_H
#include
#include
#include
#include
#include "macros.h"
/**
* @file rmid.h
* RIFF MIDI Files Input
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_FILE_EXPORT
#else
#if defined(drumstick_file_EXPORTS)
#define DRUMSTICK_FILE_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_FILE_EXPORT Q_DECL_IMPORT
#endif
#endif
namespace drumstick { namespace File {
/**
* @addtogroup RMID RIFF MIDI File Parser (Input)
* @{
*/
/**
* RIFF MIDI file format (input only)
*
* This class is used to parse RIFF MIDI Files
* @since 2.4.0
*/
class DRUMSTICK_FILE_EXPORT Rmidi : public QObject
{
Q_OBJECT
public:
explicit Rmidi(QObject * parent = nullptr);
virtual ~Rmidi();
void readFromFile(QString fileName);
void readFromStream(QDataStream* ds);
Q_SIGNALS:
/**
* @brief signalRMidInfo is emitted for each RIFF INFO element
* @param infoType Type of data (chunk ID) as defined in the spec (Source: www.midi.org rp29spec.pdf).
*
* * IARL Archival Location. Indicates where the subject of the file is archived.
* * IART Artist. Lists the artist (author) of the original subject of the file. For example: Les Getalong.
* * ICMS Commissioned. Lists the name of the person or organization that commissioned the subject of the file. For example: Acme Consolidated GameWorks.
* * ICMT Comments. Provides general comments about the file or the subject of the file. If the comment is several sentences long, end each sentence with a period. Do not include newline characters.
* * ICOP Copyright. Records the copyright information for the file. For example: Copyright Acme Consolidated GameWorks 1991. If there are multiple copyrights, separate them by a semicolon followed by a space.
* * ICRD Creation date. Specifies the date the subject of the file was created. List dates in year-month-day format, padding one-digit months and days with a zero on the left. For example: 1553-05-03 for May 3, 1553. The year should always be given using four digits.
* * IENG Engineer. Stores the name of the engineer who worked on the file. If there are multiple engineers, separate the names by a semicolon and a blank. For example: Smith, John; Adams, Joe.
* * IGNR Genre. Describes the original work, such as jazz, classical, rock, techno, rave, neo british pop grunge metal, etc.
* * IKEY Keywords. Provides a list of keywords that refer to the file or subject of the file. Separate multiple keywords with a semicolon and a blank. For example: FX; visitation; space alien.
* * IMED Medium. Describes the original subject of the file, such as record, CD and so forth.
* * INAM Name. Stores the title of the subject of the file, such as Seattle From Above.
* * IPRD Product. Specifies the name of the title the file was originally intended for, such as Galactic Ambassadors V.
* * ISBJ Subject. Describes the contents of the file, such as Music of the Gnu Whirled Order.
* * ISFT Software. Identifies the name of the software package used to create the file, such as Crash Compactor, Acme Consolidated Sonic Booms.
* * ISRC Source. Identifies the name of the person or organization who supplied the original subject of the file. For example: Acme Hysterical Media Archives.
* * ISRF Source Form. Identifies the original form of the material that was digitized, such as record, sampling CD, TV sound track and so forth. This is not necessarily the same as IMED.
* * ITCH Technician. Identifies the technician who sampled the subject file. For example: Smith, John.
*
* @param info Text data
*/
void signalRiffInfo(const QString& infoType, const QByteArray& info);
/**
* @brief signalRiffData is emitted for each RMID data element
*
* The handler of this event should use the method QSmf::readFromStream() to
* parse the contents of the SMF data element.
*
* @param dataType may be "RMID" (SMF) or "DLS"
* @param data binary payload, in RMID files is either a Standard MIDI File or a DLS structure
*/
void signalRiffData(const QString& dataType, const QByteArray& data);
private:
void read();
void processINFO(int size);
void processList(int size);
void processRMID(int size);
void processRIFF(int size);
void processData(const QString& dataType, int size);
void skip(quint32 cktype, int size);
quint32 readExpectedChunk(quint32 cktype);
quint32 readChunk(quint32& cktype);
quint32 readChunkID();
QByteArray readByteArray(int size);
QString toString(quint32 ckid);
private:
QDataStream *m_stream;
QString m_fileName;
};
/** @} */
}} // namespace drumstick::File
#endif // RMIDI_H
drumstick-2.9.0/library/include/drumstick/settingsfactory.h 0000644 0001750 0001750 00000003674 14541630232 023242 0 ustar pedro pedro /*
Drumstick Widgets
Copyright (C) 2018-2023 Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef SETTINGS_H
#define SETTINGS_H
#include
#include
#include "macros.h"
/**
* @file settingsfactory.h
* SettingsFactory class declaration
*/
#if defined(DRUMSTICK_STATIC)
#define DRUMSTICK_WIDGETS_EXPORT
#else
#if defined(drumstick_widgets_EXPORTS)
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_EXPORT
#else
#define DRUMSTICK_WIDGETS_EXPORT Q_DECL_IMPORT
#endif
#endif
/**
* @class QSettings
* @brief The QSettings class provides persistent platform-independent application settings.
* @see https://doc.qt.io/qt-5/qsettings.html
*/
namespace drumstick { namespace widgets {
/**
* @addtogroup Widgets
* @{
*
* @class SettingsFactory
* @brief The SettingsFactory class holds a global QSettings object.
* This class creates and returns a QSettings object globally configured
* instance using native or file storage.
*/
class DRUMSTICK_WIDGETS_EXPORT SettingsFactory
{
public:
QSettings *getQSettings();
QSettings *operator->();
static void setFileName(const QString name);
static QString fileName();
static QSettings::Format format();
private:
QScopedPointer m_settings{nullptr};
static QString s_fileName;
};
/** @} */
}} // namespace drumstick::widgets
#endif // SETTINGS_H
drumstick-2.9.0/library/library.pro 0000644 0001750 0001750 00000000415 14541630232 016365 0 ustar pedro pedro TEMPLATE = subdirs
SUBDIRS += \
file \
rt \
rt-backends \
vpiano-plugin \
widgets
rt-backends.depends += rt
vpiano-plugin.depends += widgets
linux {
SUBDIRS += alsa
rt-backends.depends += alsa
}
macx {
OTHER_FILES += Info.plist.lib
}
drumstick-2.9.0/library/rt-backends/ 0000755 0001750 0001750 00000000000 14541630232 016374 5 ustar pedro pedro drumstick-2.9.0/library/rt-backends/alsa-in/ 0000755 0001750 0001750 00000000000 14541630232 017720 5 ustar pedro pedro drumstick-2.9.0/library/rt-backends/alsa-in/alsa-in.pro 0000644 0001750 0001750 00000000635 14541630232 021772 0 ustar pedro pedro TEMPLATE = lib
CONFIG += c++11 plugin
static {
CONFIG += staticlib create_prl
}
TARGET = drumstick-rt-alsa-in
DESTDIR = ../../../build/lib/drumstick2
DEPENDPATH += . ../../include
INCLUDEPATH += . ../../include
include (../../../global.pri)
QT -= gui
HEADERS += alsamidiinput.h
SOURCES += alsamidiinput.cpp
LIBS += -L../../../build/lib \
-ldrumstick-rt \
-ldrumstick-alsa \
-lasound
drumstick-2.9.0/library/rt-backends/alsa-in/alsamidiinput.h 0000644 0001750 0001750 00000004454 14541630232 022743 0 ustar pedro pedro /*
Drumstick RT Backend using the ALSA Sequencer
Copyright (C) 2009-2023 Pedro Lopez-Cabanillas
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 3 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, see .
*/
#ifndef ALSAMIDIInput_H
#define ALSAMIDIInput_H
#include
#include
#include
namespace drumstick {
namespace rt {
class ALSAMIDIInput: public MIDIInput
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "net.sourceforge.drumstick.rt.MIDIInput/2.0")
Q_INTERFACES(drumstick::rt::MIDIInput)
Q_PROPERTY(QStringList diagnostics READ getDiagnostics)
Q_PROPERTY(bool status READ getStatus)
public:
explicit ALSAMIDIInput(QObject *parent = nullptr);
virtual ~ALSAMIDIInput();
// MIDIInput interface
virtual void initialize(QSettings* settings) override;
virtual QString backendName() override;
virtual QString publicName() override;
virtual void setPublicName(QString name) override;
virtual QList connections(bool advanced) override;
virtual void setExcludedConnections(QStringList conns) override;
virtual void open(const MIDIConnection& conn) override;
virtual void close() override;
virtual MIDIConnection currentConnection() override;
virtual void setMIDIThruDevice(MIDIOutput *device) override;
virtual void enableMIDIThru(bool enable) override;
virtual bool isEnabledMIDIThru() override;
static const QString DEFAULT_PUBLIC_NAME;
private:
class ALSAMIDIInputPrivate;
ALSAMIDIInputPrivate * const d;
private:
QStringList getDiagnostics();
bool getStatus();
};
}}
#endif /* ALSAMIDIInput_H */
drumstick-2.9.0/library/rt-backends/alsa-in/CMakeLists.txt 0000644 0001750 0001750 00000004567 14541630232 022474 0 ustar pedro pedro #[===========================================================================[
MIDI C++ Library
Copyright (C) 2005-2023 Pedro Lopez-Cabanillas
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 3 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, see .
#]===========================================================================]
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(drumstick-rt-alsa-in_QTOBJ_SRCS
alsamidiinput.h
)
set(drumstick-rt-alsa-in_SRCS
alsamidiinput.cpp
)
if (QT_VERSION VERSION_LESS 5.15.0)
qt5_wrap_cpp(drumstick-rt-alsa-in_MOC_SRCS ${drumstick-rt-alsa-in_QTOBJ_SRCS}
OPTIONS -I ${Drumstick_SOURCE_DIR}/library/include)
else()
qt_wrap_cpp(drumstick-rt-alsa-in_MOC_SRCS ${drumstick-rt-alsa-in_QTOBJ_SRCS}
OPTIONS -I ${Drumstick_SOURCE_DIR}/library/include)
endif()
if(STATIC_DRUMSTICK)
add_library(drumstick-rt-alsa-in STATIC
${drumstick-rt-alsa-in_MOC_SRCS}
${drumstick-rt-alsa-in_SRCS})
target_compile_definitions(drumstick-rt-alsa-in
PRIVATE QT_STATICPLUGIN)
set_target_properties(drumstick-rt-alsa-in PROPERTIES
STATIC_LIB "libdrumstick-rt-alsa-in")
else()
add_library(drumstick-rt-alsa-in MODULE
${drumstick-rt-alsa-in_MOC_SRCS}
${drumstick-rt-alsa-in_SRCS})
target_compile_definitions(drumstick-rt-alsa-in
PRIVATE QT_PLUGIN)
endif()
target_link_libraries(drumstick-rt-alsa-in PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Drumstick::ALSA
Drumstick::RT
)
set_target_properties(drumstick-rt-alsa-in PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib/${DRUMSTICK_PLUGINS_DIR})
install(TARGETS drumstick-rt-alsa-in
EXPORT drumstick-rt-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/${DRUMSTICK_PLUGINS_DIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${DRUMSTICK_PLUGINS_DIR})
drumstick-2.9.0/library/rt-backends/alsa-in/alsamidiinput.cpp 0000644 0001750 0001750 00000033343 14541630232 023275 0 ustar pedro pedro /*
Drumstick RT Backend using the ALSA Sequencer
Copyright (C) 2009-2023 Pedro Lopez-Cabanillas
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 3 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, see .
*/
#include "alsamidiinput.h"
#include
#include
#include
#include
#include
#include
namespace drumstick { namespace rt {
using namespace ALSA;
const QString ALSAMIDIInput::DEFAULT_PUBLIC_NAME = QStringLiteral("MIDI In");
class ALSAMIDIInput::ALSAMIDIInputPrivate : public SequencerEventHandler
{
public:
ALSAMIDIInput *m_inp;
MIDIOutput *m_out;
MidiClient *m_client;
MidiPort *m_port;
int m_portId;
int m_clientId;
bool m_thruEnabled;
bool m_clientFilter;
int m_runtimeAlsaNum;
QString m_publicName;
MIDIConnection m_currentInput;
QList m_inputDevices;
QStringList m_excludedNames;
bool m_initialized;
bool m_status;
QStringList m_diagnostics;
explicit ALSAMIDIInputPrivate(ALSAMIDIInput *inp) :
m_inp(inp),
m_out(nullptr),
m_client(nullptr),
m_port(nullptr),
m_portId(-1),
m_clientId(-1),
m_thruEnabled(false),
m_clientFilter(false),
m_publicName(ALSAMIDIInput::DEFAULT_PUBLIC_NAME),
m_initialized(false),
m_status(false)
{
m_runtimeAlsaNum = getRuntimeALSALibraryNumber();
}
virtual ~ALSAMIDIInputPrivate()
{
if (m_initialized) {
clearSubscription();
uninitialize();
}
}
void initialize() {
if (!m_initialized) {
m_client = new MidiClient(m_inp);
m_client->open();
m_client->setClientName(m_publicName);
m_port = m_client->createPort();
m_port->setPortName("in");
m_port->setCapability( SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE );
m_port->setPortType( SND_SEQ_PORT_TYPE_APPLICATION | SND_SEQ_PORT_TYPE_MIDI_GENERIC );
m_clientId = m_client->getClientId();
m_portId = m_port->getPortId();
m_port->setTimestamping(false);
m_port->setTimestampReal(false);
m_client->setHandler(this);
m_initialized = true;
m_status = true;
m_diagnostics.clear();
m_client->startSequencerInput();
reloadDeviceList(false);
}
//qDebug() << Q_FUNC_INFO << m_initialized;
}
void uninitialize() {
if (m_initialized) {
if (m_port != nullptr) {
m_port->detach();
delete m_port;
m_port = nullptr;
}
if (m_client != nullptr) {
m_client->close();
delete m_client;
m_client = nullptr;
}
m_initialized = false;
m_status = false;
m_diagnostics.clear();
}
//qDebug() << Q_FUNC_INFO << m_initialized;
}
bool clientIsAdvanced(int clientId)
{
// asking for runtime version instead of SND_LIB_VERSION
if (m_runtimeAlsaNum < 0x01000B)
// ALSA <= 1.0.10
return (clientId < 64);
else
// ALSA >= 1.0.11
return (clientId < 16);
}
void reloadDeviceList(bool advanced)
{
QStringList clientNames;
QMap namesMap;
if (!m_initialized) {
initialize();
}
auto inputs = m_client->getAvailableInputs();
m_clientFilter = !advanced;
m_inputDevices.clear();
m_inputDevices << MIDIConnection();
for (const PortInfo &p : std::as_const(inputs)) {
QString name = p.getClientName();
clientNames << name;
if (namesMap.contains(name)) {
namesMap[name]++;
} else {
namesMap.insert(name, 1);
}
}
for (PortInfo& p : inputs) {
bool excluded = false;
QString name = p.getClientName();
if (m_clientFilter && clientIsAdvanced(p.getClient()))
continue;
if ( m_clientFilter && name.startsWith(QStringLiteral("Virtual Raw MIDI")) )
continue;
if ( name.startsWith(m_publicName) )
continue;
for (const QString &n : std::as_const(m_excludedNames)) {
if (name.startsWith(n)) {
excluded = true;
break;
}
}
if (!excluded) {
int k = clientNames.count(name) + 1;
QString addr = QString("%1:%2").arg(p.getClient()).arg(p.getPort());
if (k > 2) {
m_inputDevices << MIDIConnection(QString("%1 (%2)").arg(name).arg(k - namesMap[name]--), addr);
} else {
m_inputDevices << MIDIConnection(name, addr);
}
}
}
if (!m_currentInput.first.isEmpty() &&
!m_inputDevices.contains(m_currentInput)) {
m_currentInput = MIDIConnection();
}
}
bool setSubscription(const MIDIConnection &newDevice)
{
//qDebug() << Q_FUNC_INFO << newDevice;
if (!m_initialized) {
initialize();
}
if (m_inputDevices.contains(newDevice)) {
m_currentInput = newDevice;
m_port->unsubscribeAll();
m_port->subscribeFrom(newDevice.second.toString());
return true;
}
return false;
}
void clearSubscription()
{
//qDebug() << Q_FUNC_INFO;
if (!m_currentInput.first.isEmpty() && m_initialized) {
m_client->stopSequencerInput();
m_port->unsubscribeAll();
m_currentInput = MIDIConnection();
}
}
void setPublicName(QString newName)
{
if (newName != m_publicName) {
m_publicName = newName;
if(m_initialized) {
m_client->setClientName(newName);
}
}
}
void handleSequencerEvent(SequencerEvent* ev) override
{
//qDebug() << Q_FUNC_INFO;
if ( !SequencerEvent::isConnectionChange(ev) && m_initialized)
switch(ev->getSequencerType()) {
case SND_SEQ_EVENT_NOTEOFF: {
const NoteOffEvent* n = static_cast(ev);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendNoteOff(n->getChannel(), n->getKey(), n->getVelocity());
}
Q_EMIT m_inp->midiNoteOff(n->getChannel(), n->getKey(), n->getVelocity());
}
break;
case SND_SEQ_EVENT_NOTEON: {
const NoteOnEvent* n = static_cast(ev);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendNoteOn(n->getChannel(), n->getKey(), n->getVelocity());
}
Q_EMIT m_inp->midiNoteOn(n->getChannel(), n->getKey(), n->getVelocity());
}
break;
case SND_SEQ_EVENT_KEYPRESS: {
const KeyPressEvent* n = static_cast(ev);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendKeyPressure(n->getChannel(), n->getKey(), n->getVelocity());
}
Q_EMIT m_inp->midiKeyPressure(n->getChannel(), n->getKey(), n->getVelocity());
}
break;
case SND_SEQ_EVENT_CONTROLLER:
case SND_SEQ_EVENT_CONTROL14: {
const ControllerEvent* n = static_cast(ev);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendController(n->getChannel(), n->getParam(), n->getValue());
}
Q_EMIT m_inp->midiController(n->getChannel(), n->getParam(), n->getValue());
}
break;
case SND_SEQ_EVENT_PGMCHANGE: {
const ProgramChangeEvent* p = static_cast(ev);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendProgram(p->getChannel(), p->getValue());
}
Q_EMIT m_inp->midiProgram(p->getChannel(), p->getValue());
}
break;
case SND_SEQ_EVENT_CHANPRESS: {
const ChanPressEvent* n = static_cast(ev);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendChannelPressure(n->getChannel(), n->getValue());
}
Q_EMIT m_inp->midiChannelPressure(n->getChannel(), n->getValue());
}
break;
case SND_SEQ_EVENT_PITCHBEND: {
const PitchBendEvent* n = static_cast(ev);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendPitchBend(n->getChannel(), n->getValue());
}
Q_EMIT m_inp->midiPitchBend(n->getChannel(), n->getValue());
}
break;
case SND_SEQ_EVENT_SYSEX: {
const SysExEvent* n = static_cast(ev);
QByteArray data(n->getData(), n->getLength());
if(m_out != nullptr && m_thruEnabled) {
m_out->sendSysex(data);
}
Q_EMIT m_inp->midiSysex(data);
}
break;
case SND_SEQ_EVENT_SYSTEM: {
const SystemEvent* n = static_cast(ev);
int status = (int) n->getRaw8(0);
if(m_out != nullptr && m_thruEnabled) {
m_out->sendSystemMsg(status);
}
if (status < 0xF7)
Q_EMIT m_inp->midiSystemCommon(status);
else if (status > 0xF7)
Q_EMIT m_inp->midiSystemRealtime(status);
}
break;
default:
break;
}
delete ev;
}
};
ALSAMIDIInput::ALSAMIDIInput(QObject *parent) : MIDIInput(parent),
d(new ALSAMIDIInputPrivate(this))
{ }
ALSAMIDIInput::~ALSAMIDIInput()
{
delete d;
}
void ALSAMIDIInput::initialize(QSettings* settings)
{
Q_UNUSED(settings)
d->initialize();
}
QString ALSAMIDIInput::backendName()
{
return QStringLiteral("ALSA");
}
QString ALSAMIDIInput::publicName()
{
return d->m_publicName;
}
void ALSAMIDIInput::setPublicName(QString name)
{
d->setPublicName(name);
}
QList ALSAMIDIInput::connections(bool advanced)
{
d->reloadDeviceList(advanced);
return d->m_inputDevices;
}
void ALSAMIDIInput::setExcludedConnections(QStringList conns)
{
d->m_excludedNames = conns;
}
void ALSAMIDIInput::open(const MIDIConnection& name)
{
//qDebug() << Q_FUNC_INFO;
auto b = d->setSubscription(name);
if (!b) {
d->m_diagnostics << "failed subscription to " + name.first;
}
}
void ALSAMIDIInput::close()
{
//qDebug() << Q_FUNC_INFO;
d->clearSubscription();
d->uninitialize();
}
MIDIConnection ALSAMIDIInput::currentConnection()
{
return d->m_currentInput;
}
void ALSAMIDIInput::setMIDIThruDevice(MIDIOutput *device)
{
d->m_out = device;
}
void ALSAMIDIInput::enableMIDIThru(bool enable)
{
d->m_thruEnabled = enable;
}
bool ALSAMIDIInput::isEnabledMIDIThru()
{
return d->m_thruEnabled && (d->m_out != nullptr);
}
QStringList ALSAMIDIInput::getDiagnostics()
{
return d->m_diagnostics;
}
bool ALSAMIDIInput::getStatus()
{
return d->m_status;
}
} // namespace rt
} // namespace drumstick
drumstick-2.9.0/library/rt-backends/alsa-out/ 0000755 0001750 0001750 00000000000 14541630232 020121 5 ustar pedro pedro drumstick-2.9.0/library/rt-backends/alsa-out/alsa-out.pro 0000644 0001750 0001750 00000000640 14541630232 022370 0 ustar pedro pedro TEMPLATE = lib
CONFIG += c++11 plugin
static {
CONFIG += staticlib create_prl
}
TARGET = drumstick-rt-alsa-out
DESTDIR = ../../../build/lib/drumstick2
DEPENDPATH += . ../../include
INCLUDEPATH += . ../../include
include (../../../global.pri)
QT -= gui
HEADERS += alsamidioutput.h
SOURCES += alsamidioutput.cpp
LIBS += -L../../../build/lib \
-ldrumstick-rt \
-ldrumstick-alsa \
-lasound
drumstick-2.9.0/library/rt-backends/alsa-out/CMakeLists.txt 0000644 0001750 0001750 00000004622 14541630232 022665 0 ustar pedro pedro #[===========================================================================[
MIDI C++ Library
Copyright (C) 2005-2023 Pedro Lopez-Cabanillas
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 3 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, see .
#]===========================================================================]
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(drumstick-rt-alsa-out_QTOBJ_SRCS
alsamidioutput.h
)
set(drumstick-rt-alsa-out_SRCS
alsamidioutput.cpp
)
if (QT_VERSION VERSION_LESS 5.15.0)
qt5_wrap_cpp(drumstick-rt-alsa-out_MOC_SRCS ${drumstick-rt-alsa-out_QTOBJ_SRCS}
OPTIONS -I ${Drumstick_SOURCE_DIR}/library/include)
else()
qt_wrap_cpp(drumstick-rt-alsa-out_MOC_SRCS ${drumstick-rt-alsa-out_QTOBJ_SRCS}
OPTIONS -I ${Drumstick_SOURCE_DIR}/library/include)
endif()
if(STATIC_DRUMSTICK)
add_library(drumstick-rt-alsa-out STATIC
${drumstick-rt-alsa-out_MOC_SRCS}
${drumstick-rt-alsa-out_SRCS})
target_compile_definitions(drumstick-rt-alsa-out
PRIVATE QT_STATICPLUGIN)
set_target_properties(drumstick-rt-alsa-out PROPERTIES
STATIC_LIB "libdrumstick-rt-alsa-out")
else()
add_library(drumstick-rt-alsa-out MODULE
${drumstick-rt-alsa-out_MOC_SRCS}
${drumstick-rt-alsa-out_SRCS}
)
target_compile_definitions(drumstick-rt-alsa-out
PRIVATE QT_PLUGIN)
endif()
target_link_libraries(drumstick-rt-alsa-out PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Drumstick::ALSA
Drumstick::RT
)
set_target_properties(drumstick-rt-alsa-out PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib/${DRUMSTICK_PLUGINS_DIR})
install(TARGETS drumstick-rt-alsa-out
EXPORT drumstick-rt-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/${DRUMSTICK_PLUGINS_DIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${DRUMSTICK_PLUGINS_DIR})
drumstick-2.9.0/library/rt-backends/alsa-out/alsamidioutput.cpp 0000644 0001750 0001750 00000023615 14541630232 023700 0 ustar pedro pedro /*
Drumstick RT Backend using the ALSA Sequencer
Copyright (C) 2009-2023 Pedro Lopez-Cabanillas
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 3 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, see .
*/
#include "alsamidioutput.h"
#include
#include
#include