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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# v1.12.0

* add _Mixed Data Set_ support: `mixed_data_set_header_packet` / `mixed_data_set_payload_packet` incl. views and factory functions
* add `mixed_data_set` with `send_mixed_data_set` / `as_mixed_data_set_packets`
* add `mixed_data_set_collector` reassembling _Mixed Data Sets_ from incoming packets (16 simultaneous `mds_id`s)

# v1.11.0

* add data_byte accessors to `flex_data_message_view`
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ set(LibSources
inc/midi/data_message.h
inc/midi/extended_data_message.h
inc/midi/flex_data_message.h
inc/midi/mixed_data_set.h
inc/midi/mixed_data_set_collector.h src/mixed_data_set_collector.cpp
inc/midi/stream_message.h
inc/midi/sysex.h src/sysex.cpp
inc/midi/sysex_collector.h src/sysex_collector.cpp
Expand Down Expand Up @@ -91,6 +93,9 @@ if( NIMIDI2_TESTS )
tests/data_message_tests.cpp
tests/extended_data_message_tests.cpp
tests/flex_data_message_tests.cpp
tests/mixed_data_set_tests.cpp
tests/mixed_data_set_test_data.cpp tests/mixed_data_set_test_data.h
tests/mixed_data_set_collector_tests.cpp
tests/stream_message_tests.cpp
tests/system_message_tests.cpp
tests/utility_message_tests.cpp
Expand Down Expand Up @@ -136,6 +141,7 @@ if( NIMIDI2_EXAMPLES )
docs/data_message.examples.cpp
docs/extended_data_message.examples.cpp
docs/flex_data_message.examples.cpp
docs/mixed_data_set.examples.cpp
docs/midi1_byte_stream.examples.cpp
docs/midi1_channel_voice_message.examples.cpp
docs/midi2_channel_voice_message.examples.cpp
Expand Down
2 changes: 2 additions & 0 deletions docs/docs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ extern void run_channel_voice_message_examples();
extern void run_data_message_examples();
extern void run_extended_data_message_examples();
extern void run_flex_data_message_examples();
extern void run_mixed_data_set_examples();
extern void run_midi1_byte_stream_examples();
extern void run_midi1_channel_voice_message_examples();
extern void run_midi2_channel_voice_message_examples();
Expand Down Expand Up @@ -29,6 +30,7 @@ int main()

run_stream_message_examples();
run_flex_data_message_examples();
run_mixed_data_set_examples();

return 0;
}
51 changes: 51 additions & 0 deletions docs/mixed_data_set.examples.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <midi/manufacturer.h>
#include <midi/mixed_data_set.h>
#include <midi/mixed_data_set_collector.h>

#include <cassert>

void mixed_data_set_examples()
{
using namespace midi;

// a mixed data set with some payload data
mixed_data_set mds{ manufacturer::native_instruments, 0, 0, 0 };
mds.data = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };

for (const auto& p : as_mixed_data_set_packets(mds, 0x0))
{
// send packet
// ...
(void)p;
}

// or send packets without allocating a vector
send_mixed_data_set(mds, 0x0, 0, [](const universal_packet& p) {
// send packet
// ...
(void)p;
});
}

void mixed_data_set_collector_examples()
{
using namespace midi;

universal_packet p;

mixed_data_set_collector c{ [](const mixed_data_set& mds, uint4_t mds_id) {
// do something with message
// ...
(void)mds;
(void)mds_id;
} };

if (is_mixed_data_set_packet(p))
c.feed(p);
}

void run_mixed_data_set_examples()
{
mixed_data_set_examples();
mixed_data_set_collector_examples();
}
101 changes: 101 additions & 0 deletions docs/mixed_data_set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Mixed Data Set

Code examples can be found in [`mixed_data_set.examples.cpp`](mixed_data_set.examples.cpp).

_Mixed Data Set_ messages allow transfer of arbitrary (8 bit) data, the data being
split into _chunks_, each chunk consisting of a _header_ packet followed by _payload_
packets (14 data bytes per packet). Up to 16 _Mixed Data Sets_ (distinguished by
their `mds_id`) can be transmitted simultaneously within a group.

A complete _Mixed Data Set_ is represented by

```cpp
struct mixed_data_set
{
using data_type = std::vector<uint8_t>;

manufacturer_t manufacturerID;
uint16_t deviceID; // 0xFFFF means 'all call'
uint16_t subID1;
uint16_t subID2;
data_type data;

mixed_data_set(manufacturer_t);
mixed_data_set(manufacturer_t, uint16_t device_id, uint16_t sub_id_1, uint16_t sub_id_2);
mixed_data_set(manufacturer_t, uint16_t device_id, uint16_t sub_id_1, uint16_t sub_id_2, data_type);

void clear();
};
```

Like in _System Exclusive_ messages, `deviceID`, `subID1` and `subID2` are defined by
other MMA/AMEI specifications when `manufacturerID` is a Universal SysEx ID, otherwise
their use is defined by the manufacturer.

On the wire the manufacturer ID is encoded in 16 bits, conversions are available
in `manufacturer.h` as

```cpp
constexpr uint16_t manufacturer_id_16bit(manufacturer_t);
constexpr manufacturer_t manufacturer_from_16bit_id(uint16_t);
```

## Message Creation and Filtering

Individual packets are represented by `mixed_data_set_header_packet` and
`mixed_data_set_payload_packet` (in `extended_data_message.h`), with corresponding
factory functions, filters and views:

```cpp
mixed_data_set_header_packet make_mixed_data_set_header_packet(uint4_t mds_id, group_t = 0);
mixed_data_set_payload_packet make_mixed_data_set_payload_packet(uint4_t mds_id, group_t = 0);

bool is_mixed_data_set_header_packet(const universal_packet&);
bool is_mixed_data_set_payload_packet(const universal_packet&);
bool is_mixed_data_set_packet(const universal_packet&);

std::optional<mixed_data_set_header_packet_view> as_mixed_data_set_header_packet_view(const universal_packet&);
std::optional<mixed_data_set_payload_packet_view> as_mixed_data_set_payload_packet_view(const universal_packet&);
```

## Sending Mixed Data Sets

Usually one does not create _Mixed Data Set_ packets manually, but uses

```cpp
template<typename Sender>
void send_mixed_data_set(const mixed_data_set&, uint4_t mds_id, group_t, Sender&&);

std::vector<extended_data_message> as_mixed_data_set_packets(const mixed_data_set&, uint4_t mds_id, group_t = 0);
```

`send_mixed_data_set` splits the data into chunks and packets and forwards them to
`sender(p)`. `as_mixed_data_set_packets` returns the resulting packets in a vector
instead.

## Collecting Mixed Data Sets

Use `mixed_data_set_collector` to reassemble _Mixed Data Sets_ from incoming packets:

```cpp
class mixed_data_set_collector
{
public:
using callback = std::function<void(const mixed_data_set&, uint4_t mds_id)>;

explicit mixed_data_set_collector(callback);

void set_callback(callback);
void set_max_data_size(size_t); // limit maximum size of accepted mixed data set data

void feed(const universal_packet&);
void reset();
};
```

Feed incoming packets into `feed()`. Once the final chunk of a _Mixed Data Set_ is
complete the callback is invoked with the reassembled `mixed_data_set` and its
`mds_id`. The collector maintains an independent collection state per `mds_id`, so
interleaved _Mixed Data Sets_ are supported. Aborted messages (a header with
_Number of this Chunk_ set to zero), out-of-order chunks and invalid headers discard
the collection state of the affected `mds_id`.
Loading
Loading