Program Listing for File libremidi.hpp

Return to documentation for file (include/libremidi/libremidi.hpp)

#pragma once
/* This software is based on the RtMidi and ModernMidi libraries.

  RtMidi WWW site: http://music.mcgill.ca/~gary/libremidi/

  RtMidi: realtime MIDI i/o C++ classes
  Copyright (c) 2003-2017 Gary P. Scavone

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation files
  (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge,
  publish, distribute, sublicense, and/or sell copies of the Software,
  and to permit persons to whom the Software is furnished to do so,
  subject to the following conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  Any person wishing to distribute modifications to the Software is
  asked to send the modifications to the original developer so that
  they can be incorporated into the canonical version.  This is,
  however, not a binding provision of this license.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 ------------

  ModernMidi Copyright (c) 2015, Dimitri Diakopoulos All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
*/

#include <libremidi/message.hpp>

#include <algorithm>
#include <cassert>
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>

#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002
#define LIBREMIDI_HAS_SPAN 1
#include <span>
#endif

#if defined(LIBREMIDI_EXPORTS)
#  if defined(_MSC_VER)
#    define LIBREMIDI_EXPORT __declspec(dllexport)
#  elif defined(__GNUC__) || defined(__clang__)
#    define LIBREMIDI_EXPORT __attribute__((visibility("default")))
#  endif
#else
#  define LIBREMIDI_EXPORT
#endif

#define LIBREMIDI_VERSION "1.0.0"

namespace libremidi
{
enum midi_error
{
  WARNING,
  UNSPECIFIED,
  NO_DEVICES_FOUND,
  INVALID_DEVICE,
  MEMORY_ERROR,
  INVALID_PARAMETER,
  INVALID_USE,
  DRIVER_ERROR,
  SYSTEM_ERROR,
  THREAD_ERROR
};

struct LIBREMIDI_EXPORT midi_exception : public std::runtime_error
{
  using std::runtime_error::runtime_error;
  ~midi_exception() override;
};

struct LIBREMIDI_EXPORT no_devices_found_error final : public midi_exception
{
  static constexpr auto code = midi_error::NO_DEVICES_FOUND;
  using midi_exception::midi_exception;
  ~no_devices_found_error() override;
};
struct LIBREMIDI_EXPORT invalid_device_error final : public midi_exception
{
  static constexpr auto code = midi_error::INVALID_DEVICE;
  using midi_exception::midi_exception;
  ~invalid_device_error() override;
};
struct LIBREMIDI_EXPORT memory_error final : public midi_exception
{
  static constexpr auto code = midi_error::MEMORY_ERROR;
  using midi_exception::midi_exception;
  ~memory_error() override;
};
struct LIBREMIDI_EXPORT invalid_parameter_error final : public midi_exception
{
  static constexpr auto code = midi_error::INVALID_PARAMETER;
  using midi_exception::midi_exception;
  ~invalid_parameter_error() override;
};
struct LIBREMIDI_EXPORT invalid_use_error final : public midi_exception
{
  static constexpr auto code = midi_error::INVALID_USE;
  using midi_exception::midi_exception;
  ~invalid_use_error() override;
};
struct LIBREMIDI_EXPORT driver_error final : public midi_exception
{
  static constexpr auto code = midi_error::DRIVER_ERROR;
  using midi_exception::midi_exception;
  ~driver_error() override;
};
struct LIBREMIDI_EXPORT system_error final : public midi_exception
{
  static constexpr auto code = midi_error::SYSTEM_ERROR;
  using midi_exception::midi_exception;
  ~system_error() override;
};
struct LIBREMIDI_EXPORT thread_error final : public midi_exception
{
  static constexpr auto code = midi_error::THREAD_ERROR;
  using midi_exception::midi_exception;
  ~thread_error() override;
};

using midi_error_callback = std::function<void(midi_error type, std::string_view errorText)>;

enum class API
{
  UNSPECIFIED,
  MACOSX_CORE,
  LINUX_ALSA,
  LINUX_ALSA_SEQ = LINUX_ALSA,
  LINUX_ALSA_RAW,
  UNIX_JACK,
  WINDOWS_MM,
  WINDOWS_UWP,
  EMSCRIPTEN_WEBMIDI,
  DUMMY
};

std::vector<libremidi::API> available_apis() noexcept;

std::string get_version() noexcept;

class LIBREMIDI_EXPORT observer
{
public:
  struct callbacks
  {
    std::function<void(int, std::string)> input_added;
    std::function<void(int, std::string)> input_removed;
    std::function<void(int, std::string)> output_added;
    std::function<void(int, std::string)> output_removed;
  };

  observer(libremidi::API, callbacks);
  ~observer();

private:
  std::unique_ptr<class observer_api> impl_;
};

struct LIBREMIDI_EXPORT chunking_parameters {
  std::chrono::milliseconds interval{};
  int32_t size{};

  std::function<bool(std::chrono::microseconds, int)> wait = chunking_parameters::default_wait;

  static bool default_wait(std::chrono::microseconds time_to_wait, int written_bytes);
};

/**********************************************************************/
class LIBREMIDI_EXPORT midi_in
{
public:
  using message_callback = std::function<void(const message& message)>;


  midi_in(
      libremidi::API api = API::UNSPECIFIED,
      std::string_view clientName = "RtMidi Input Client",
      unsigned int queueSizeLimit = 100);

  ~midi_in();

  libremidi::API get_current_api() const noexcept;


  void open_port(unsigned int portNumber, std::string_view portName);
  void open_port()
  {
    open_port(0, "libremidi Input");
  }
  void open_port(unsigned int port)
  {
    open_port(port, "libremidi Input");
  }


  void open_virtual_port(std::string_view portName);
  void open_virtual_port()
  {
    open_virtual_port("libremidi virtual port");
  }

  void set_callback(message_callback callback);


  void cancel_callback();

  void close_port();


  bool is_port_open() const noexcept;


  unsigned int get_port_count();


  std::string get_port_name(unsigned int portNumber = 0);


  void ignore_types(bool midiSysex = true, bool midiTime = true, bool midiSense = true);


  message get_message();

  bool get_message(message&);


  void set_error_callback(midi_error_callback errorCallback);

  void set_client_name(std::string_view clientName);

  void set_port_name(std::string_view portName);

private:
  std::unique_ptr<class midi_in_api> rtapi_;
};

/**********************************************************************/
/**********************************************************************/

class LIBREMIDI_EXPORT midi_out
{
public:

  midi_out(libremidi::API api, std::string_view clientName);

  midi_out() : midi_out{libremidi::API::UNSPECIFIED, "RtMidi client"}
  {
  }

  ~midi_out();

  libremidi::API get_current_api() noexcept;


  void open_port(unsigned int portNumber, std::string_view portName);
  void open_port()
  {
    open_port(0, "libremidi Output");
  }
  void open_port(unsigned int port)
  {
    open_port(port, "libremidi Output");
  }

  void close_port();


  bool is_port_open() const noexcept;


  void open_virtual_port(std::string_view portName);
  void open_virtual_port()
  {
    open_virtual_port("libremidi virtual port");
  }

  unsigned int get_port_count();


  std::string get_port_name(unsigned int portNumber = 0);


  void send_message(const std::vector<unsigned char>& message);

  void send_message(const libremidi::message& message);


  void send_message(const unsigned char* message, size_t size);

  #if LIBREMIDI_HAS_SPAN
  void send_message(std::span<unsigned char>);
  #endif


  void set_error_callback(midi_error_callback errorCallback) noexcept;

  void set_client_name(std::string_view clientName);

  void set_port_name(std::string_view portName);

  void set_chunking_parameters(std::optional<chunking_parameters> parameters);

private:
  std::unique_ptr<class midi_out_api> rtapi_;
};
}

#if defined(LIBREMIDI_HEADER_ONLY)
#  include <libremidi/libremidi.cpp>
#endif