Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmake/libremidi.examples.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_example(midiobserve)
add_example(echo)
add_example(cmidiin)
add_example(cmidiin2)
add_example(lookup)
add_example(midi1_to_midi2)
add_example(midiclock_in)
add_example(midiclock_out)
Expand Down
2 changes: 2 additions & 0 deletions cmake/libremidi.sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ target_sources(libremidi PRIVATE
include/libremidi/input_configuration.hpp
include/libremidi/libremidi.hpp
include/libremidi/message.hpp
include/libremidi/port_comparison.hpp
include/libremidi/port_information.hpp
include/libremidi/output_configuration.hpp
include/libremidi/ump_events.hpp

Expand Down
61 changes: 61 additions & 0 deletions examples/lookup.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// midiprobe.cpp
//
// Simple program to check MIDI inputs and outputs.
//
// by Gary Scavone, 2003-2012.

#include "utils.hpp"

#include <libremidi/libremidi.hpp>
#include <libremidi/port_comparison.hpp>

#if defined(_WIN32) && __has_include(<winrt/base.h>)
#include <winrt/base.h>
#endif

#include <chrono>
#include <cstdlib>
#include <iostream>
#include <thread>

void lookup_api(libremidi::API api, const libremidi::input_port& searched)
{
std::string_view api_name = libremidi::get_api_display_name(api);
std::cout << "Displaying ports for: " << api_name << std::endl;

// On Windows 10, apparently the MIDI devices aren't exactly available as soon as the app open...
std::this_thread::sleep_for(std::chrono::milliseconds(100));

libremidi::observer midi{
{.track_hardware = true, .track_virtual = true}, libremidi::observer_configuration_for(api)};

std::this_thread::sleep_for(std::chrono::milliseconds(100));

{
// Check inputs.
auto ports = midi.get_input_ports();
auto res = libremidi::find_closest_port(searched, ports);
if (res.found) {
std::cout << "Found: " << *res.port << "\n";
}
}
}

int main()
{
#if defined(_WIN32) && __has_include(<winrt/base.h>)
// Necessary for using WinUWP and WinMIDI, must be done as early as possible in your main()
winrt::init_apartment();
#endif

// This will find the port that is closest to this.
// For instance, given a Launchpad and a Launchpad Mini,
// the launchpad will be returned. Otherwise, the mini will be returned.
libremidi::input_port searched{{.port_name = "launchpad"}};

for (auto& api : libremidi::available_apis())
lookup_api(api, searched);
for (auto& api : libremidi::available_ump_apis())
lookup_api(api, searched);
return 0;
}
9 changes: 4 additions & 5 deletions examples/midiprobe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@

void enumerate_api(libremidi::API api)
{
#if defined(_WIN32) && __has_include(<winrt/base.h>)
// Necessary for using WinUWP and WinMIDI, must be done as early as possible in your main()
winrt::init_apartment();
#endif

std::string_view api_name = libremidi::get_api_display_name(api);
std::cout << "Displaying ports for: " << api_name << std::endl;

Expand Down Expand Up @@ -58,6 +53,10 @@ void enumerate_api(libremidi::API api)

int main()
{
#if defined(_WIN32) && __has_include(<winrt/base.h>)
// Necessary for using WinUWP and WinMIDI, must be done as early as possible in your main()
winrt::init_apartment();
#endif
for (auto& api : libremidi::available_apis())
enumerate_api(api);
for (auto& api : libremidi::available_ump_apis())
Expand Down
2 changes: 1 addition & 1 deletion include/libremidi/backends/jack/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ struct jack_client
.client = reinterpret_cast<std::uintptr_t>(client),
.port = 0,
.manufacturer = "",
.device_name = "",
.device_name = jack_get_client_name(client),
.port_name = jack_port_name(port),
.display_name = get_port_display_name(port),
}};
Expand Down
123 changes: 1 addition & 122 deletions include/libremidi/observer_configuration.hpp
Original file line number Diff line number Diff line change
@@ -1,129 +1,8 @@
#pragma once
#include <libremidi/api.hpp>
#include <libremidi/config.hpp>
#include <libremidi/error.hpp>
#include <libremidi/types.hpp>

#include <array>
#include <compare>
#include <string>
#include <variant>
#include <libremidi/port_information.hpp>

namespace libremidi
{
struct LIBREMIDI_EXPORT port_information
{
// Compat
using port_type = libremidi::transport_type;

/// Which API is this port for. port_information objects are in general
/// not useable for different APIs than the API of the observer that created them.
libremidi::API api{};

/// Handle to the API client object if the API provides one
// ALSA Raw: unused
// ALSA Seq: snd_seq_t*
// CoreMIDI: MidiClientRef
// JACK: jack_client_t*
// PipeWire: unused // FIXME: pw_context? pw_main_loop?
// WebMIDI: unused
// WinMIDI: TODO
// WinMM: unused
// WinUWP: unused
client_handle client = static_cast<client_handle>(-1);

/// Container identifier if the API provides one
// ALSA: device id (std::string), e.g. ID_PATH as returned by udev: "pci-0000:00:14.0-usb-0:12:1.0"
// CoreMIDI: USBLocationID (int32_t)
// WinMIDI: ContainerID GUID (bit_cast to a winapi or winrt::GUID ;
// this is not the string but the binary representation).
container_identifier container = std::monostate{};

/// Device identifier if the API provides one
// ALSA: sysfs path (std::string), e.g. "/sys/devices/pci0000:00/0000:00:02.2/0000:02:00.0/sound/card0/controlC0"
// CoreMIDI: USBVendorProduct (int32_t)
// WinMIDI: EndpointDeviceId (std::string), e.g. "\\?\swd#midisrv#midiu_ksa..."
// WinMM: MIDI{IN,OUT}CAPS mId / pId { uint16_t manufacturer_id, uint16_t product_id; }
device_identifier device = std::monostate{};

/// Handle to the port identifier if the API provides one
// ALSA Raw: bit_cast to struct { uint16_t card, device, sub, padding; }.
// ALSA Seq: bit_cast to struct { uint32_t client, port; }
// CoreMIDI: MidiObjectRef's kMIDIPropertyUniqueID (uint32_t)
// JACK: jack_port_id_t
// PipeWire: port.id
// WebMIDI: index of the MIDI device in the list provided by the browser.
// WinMIDI: uint64_t terminal_block_number; (MidiGroupTerminalBlock::Number(), index is 1-based)
// WinMM: port index between 0 and midi{In,Out}GetNumDevs()
// WinUWP: index of the MIDI device in the list provided by the OS.
port_handle port = static_cast<port_handle>(-1);

/// User-readable information
// ALSA Raw: ID_VENDOR_FROM_DATABASE if provided by udev
// ALSA Seq: ID_VENDOR_FROM_DATABASE if provided by udev
// CoreMIDI: kMIDIPropertyManufacturer
// WinMIDI: MidiEndpointDeviceInformation::GetTransportSuppliedInfo().ManufacturerName
// WinMM: unavailable
std::string manufacturer{};

// ALSA Raw: ID_MODEL_FROM_DATABASE if provided by udev
// ALSA Seq: ID_MODEL_FROM_DATABASE if provided by udev
// WinMIDI: MidiEndpointDeviceInformation::GetTransportSuppliedInfo().Name
std::string product{};

/// "Unique" serial number. Note that this is super unreliable - pretty
/// much no MIDI device manufacturer bothers with unique per-device serial number
/// unlike most USB devices.
// ALSA Raw: ID_USB_SERIAL if provided by udev.
// ALSA Seq: ID_USB_SERIAL if provided by udev.
// WinMIDI: MidiEndpointDeviceInformation::GetTransportSuppliedInfo().SerialNumber
std::string serial{};

// ALSA Raw: Name returned by snd_rawmidi_info_get_name
// ALSA Seq: Name returned by snd_seq_client_info_get_name
// CoreMIDI: kMIDIPropertyModel
// WinMIDI: MidiEndpointDeviceInformation::Name
// WinMM: unavailable
std::string device_name{};

// ALSA Raw: Name returned by snd_rawmidi_info_get_subdevice_name
// ALSA Seq: Name returned by snd_seq_port_info_get_name
// CoreMIDI: kMIDIPropertyName
// WinMIDI: MidiGroupTerminalBlock::Name
// WinMM: szPname
std::string port_name{};

// CoreMIDI: kMIDIPropertyDisplayName
// Otherwise: the closest to a unique name we can get
std::string display_name{};

/// Port type
// CoreMIDI: available
// WinMIDI: available
// WinMM: unavailable
port_type type = port_type::unknown;

// Equality and comparison operators are deleted as there is not one
// single correct way to compare two port_information:
// in some cases it may be useful to only compare the names, while in other cases
// it is necessary to check whether this is the exact same low-level identifier.
// Thus, the end-user must define their own custom equality operators
// if using std:: containers or algorithms
bool operator==(const port_information& other) const noexcept = delete;
std::strong_ordering operator<=>(const port_information& other) const noexcept = delete;
};

struct input_port : port_information
{
bool operator==(const input_port& other) const noexcept = delete;
std::strong_ordering operator<=>(const input_port& other) const noexcept = delete;
};
struct output_port : port_information
{
bool operator==(const output_port& other) const noexcept = delete;
std::strong_ordering operator<=>(const output_port& other) const noexcept = delete;
};

using input_port_callback = std::function<void(const input_port&)>;
using output_port_callback = std::function<void(const output_port&)>;
struct observer_configuration
Expand Down
Loading