Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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();
}
100 changes: 100 additions & 0 deletions docs/mixed_data_set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# 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 as

```cpp
constexpr uint16_t mixed_data_set_manufacturer_id(manufacturer_t);
constexpr manufacturer_t manufacturer_from_mixed_data_set_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