|
| 1 | +//===-- Demo CI Message Dispatch ----------------------------------------------*- C++ -*-===// |
| 2 | +// |
| 3 | +// midi2 library under the MIT license. |
| 4 | +// See https://github.com/paulhuggett/AM_MIDI2.0Lib/blob/main/LICENSE for license information. |
| 5 | +// SPDX-License-Identifier: MIT |
| 6 | +// |
| 7 | +//===------------------------------------------------------------------------------------===// |
| 8 | + |
1 | 9 | #include "midi2/ci_dispatcher.hpp"
|
2 | 10 |
|
3 | 11 | #include <array>
|
4 | 12 | #include <cstdlib>
|
5 |
| -#include <ctime> |
6 | 13 | #include <format>
|
7 | 14 | #include <iostream>
|
8 |
| -#include <random> |
9 |
| -#include <ranges> |
| 15 | +#include <type_traits> |
10 | 16 |
|
11 |
| -namespace { |
| 17 | +using namespace midi2::ci::literals; |
12 | 18 |
|
13 |
| -template <std::ranges::input_range Range> std::string as_string(Range const &range) { |
14 |
| - std::string result; |
15 |
| - char const *separator = ""; |
16 |
| - for (auto const v : range) { |
17 |
| - result += std::format("{}0x{:X}", separator, v); |
18 |
| - separator = ", "; |
| 19 | +// A formatter for arrays of 7-bit integer values (b7). These will be represented to |
| 20 | +// comma-separated hex values. |
| 21 | +template <std::size_t Size, typename CharT> struct std::formatter<std::array<midi2::ci::b7, Size>, CharT> { |
| 22 | + constexpr auto parse(auto &parse_ctx) const { return parse_ctx.begin(); } |
| 23 | + auto format(std::array<midi2::ci::b7, Size> const &arr, auto &format_ctx) const { |
| 24 | + // NOLINTNEXTLINE(llvm-qualified-auto,readability-qualified-auto) |
| 25 | + auto out = format_ctx.out(); |
| 26 | + char const *separator = ""; |
| 27 | + for (auto const value : arr) { |
| 28 | + out = std::format_to(out, "{}0x{:X}", separator, value); |
| 29 | + separator = ","; |
| 30 | + } |
| 31 | + return out; |
19 | 32 | }
|
20 |
| - return result; |
| 33 | +}; |
| 34 | + |
| 35 | +namespace { |
| 36 | +// Display the header fields |
| 37 | +void print_header(std::ostream &os, midi2::ci::header const &h) { |
| 38 | + os << std::format("device-id=0x{:X}\nversion=0x{:X}\n", h.device_id, h.version) |
| 39 | + << std::format("remote-MUID=0x{:X}\nlocal-MUID=0x{:X}\n\n", h.remote_muid, h.local_muid); |
| 40 | +} |
| 41 | +// Display the discovery data fields |
| 42 | +void print_discovery(std::ostream &os, midi2::ci::discovery const &d) { |
| 43 | + os << std::format("manufacturer={}\nfamily=0x{:X}\nmodel=0x{:X}\n", d.manufacturer, d.family, d.model) |
| 44 | + << std::format("version={}\ncapability=0x{:X}\n", d.version, d.capability) |
| 45 | + << std::format("max-sysex-size=0x{:X}\noutput-path-id=0x{:X}\n", d.max_sysex_size, d.output_path_id); |
21 | 46 | }
|
22 | 47 |
|
23 |
| -} // end anonymous namespace |
| 48 | +// We must pass a “context” to the dispatcher, which will be forwarded to each of the dispatcher's callbacks. |
| 49 | +// The context lets message handlers share state but we don’t need that here, so a struct with no members will suffice. |
| 50 | +struct context {}; |
24 | 51 |
|
25 |
| -int main() { |
26 |
| - // Generate a random local MUID. |
27 |
| - std::mt19937 engine{std::random_device{}()}; |
28 |
| - std::uniform_int_distribution<std::uint32_t> distribution; |
29 |
| - auto const local_muid = distribution(engine) % midi2::ci::max_user_muid; |
| 52 | +// Normally, these typedefs are not necessary: just use auto! However, |
| 53 | +// they are included here for clarity. |
| 54 | +constexpr auto buffer_size = std::size_t{256}; |
| 55 | +using function_config = midi2::ci::function_config<context, buffer_size>; |
| 56 | +static_assert(std::is_same_v<std::remove_cvref_t<decltype(function_config::buffer_size)>, std::size_t>); |
| 57 | +using dispatcher = midi2::ci::ci_dispatcher<function_config>; |
30 | 58 |
|
31 |
| - struct context {}; |
| 59 | +dispatcher setup_ci_dispatcher(midi2::ci::muid const my_muid) { |
32 | 60 | // Create a CI dispatcher instance using std::function<> for all of its handler functions.
|
33 |
| - auto dispatcher = midi2::ci::make_function_dispatcher(context{}); |
| 61 | + auto dispatcher = midi2::ci::make_function_dispatcher<context, buffer_size>(); |
34 | 62 | auto &config = dispatcher.config();
|
35 |
| - // Register a handler for checking whether a message is address to this MUID. |
| 63 | + |
| 64 | + // Register a handler for checking whether a message is addressed to this receiver. |
36 | 65 | config.system.on_check_muid(
|
37 |
| - [&local_muid](context, std::uint8_t /*group*/, std::uint32_t const muid) { return local_muid == muid; }); |
| 66 | + [my_muid](context, std::uint8_t /*group*/, midi2::ci::muid const m) { return m == my_muid; }); |
| 67 | + |
38 | 68 | // Register a handler for Discovery messages.
|
39 |
| - config.management.on_discovery([](context, midi2::ci::header const &hdr, midi2::ci::discovery const &d) { |
40 |
| - // Display the header fields |
41 |
| - std::cout << std::format("device-id=0x{:X}\nversion=0x{:X}\n", hdr.device_id, hdr.version) |
42 |
| - << std::format("remote-MUID=0x{:08X}\nlocal-MUID=0x{:08X}\n\n", hdr.remote_muid, hdr.local_muid); |
43 |
| - |
44 |
| - // Display the discovery data fields |
45 |
| - std::cout << std::format("manufacturer=[{}]\nfamily=0x{:X}\nmodel=0x{:X}\n", as_string(d.manufacturer), d.family, |
46 |
| - d.model) |
47 |
| - << std::format("version=[{}]\n", as_string(d.version)) |
48 |
| - << std::format("capability=0x{:X}\nmax-sysex-size=0x{:X}\noutput-path-id=0x{:X}\n", d.capability, |
49 |
| - d.max_sysex_size, d.output_path_id); |
| 69 | + config.management.on_discovery([](context, midi2::ci::header const &h, midi2::ci::discovery const &d) { |
| 70 | + print_header(std::cout, h); |
| 71 | + print_discovery(std::cout, d); |
50 | 72 | // Send a reply to this message...
|
51 | 73 | });
|
| 74 | + return dispatcher; |
| 75 | +} |
| 76 | +} // end anonymous namespace |
| 77 | + |
| 78 | +int main() { |
| 79 | + constexpr auto my_muid = midi2::ci::muid{0x01234567U}; // Use a proper random number! |
| 80 | + constexpr auto my_group = std::uint8_t{0}; |
| 81 | + constexpr auto device_id = 0_b7; |
| 82 | + auto dispatcher = setup_ci_dispatcher(my_muid); |
52 | 83 |
|
| 84 | + // A system exclusive message containing a CI discovery request. |
53 | 85 | constexpr std::array message{0x7E, 0x7F, 0x0D, 0x70, 0x02, 0x00, 0x00, 0x00, 0x00, 0x7F,
|
54 | 86 | 0x7F, 0x7F, 0x7F, 0x12, 0x23, 0x34, 0x79, 0x2E, 0x5D, 0x56,
|
55 |
| - 0x4E, 0x3C, 0x2A, 0x18, 0x7F, 0x00, 0x02, 0x00, 0x00, 0x71}; |
56 |
| - constexpr auto group = std::uint8_t{0}; |
57 |
| - constexpr auto device_id = std::byte{0}; |
58 |
| - dispatcher.start(group, device_id); |
| 87 | + 0x01, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x02, 0x00, 0x00, 0x00}; |
| 88 | + dispatcher.start(my_group, device_id); |
59 | 89 | for (auto const b : message) {
|
60 | 90 | dispatcher.processMIDICI(static_cast<std::byte>(b));
|
61 | 91 | }
|
|
0 commit comments