diff --git a/lib/guid.dart b/lib/guid.dart new file mode 100644 index 0000000..51e2720 --- /dev/null +++ b/lib/guid.dart @@ -0,0 +1,108 @@ +class Guid { + final List bytes; + + Guid.empty() : bytes = List.filled(16, 0); + + Guid.fromBytes(this.bytes) + : assert(_checkLen(bytes.length), 'GUID must be 16, 32, or 128 bit.'); + + Guid.fromString(String input) : bytes = _fromString(input); + + Guid(String input) : bytes = _fromString(input); + + static List _fromString(String input) { + if (input.isEmpty) { + return List.filled(16, 0); + } + + input = input.replaceAll('-', ''); + + List? bytes = _tryHexDecode(input); + if (bytes == null) { + throw FormatException("GUID not hex format: $input"); + } + + _checkLen(bytes.length); + + return bytes; + } + + static bool _checkLen(int len) { + if (!(len == 16 || len == 4 || len == 2)) { + throw FormatException( + "GUID must be 16, 32, or 128 bit, yours: ${len * 8}-bit", + ); + } + return true; + } + + static List? _tryHexDecode(String hex) { + List numbers = []; + for (int i = 0; i < hex.length; i += 2) { + String hexPart = hex.substring(i, i + 2); + int? num = int.tryParse(hexPart, radix: 16); + if (num == null) { + return null; + } + numbers.add(num); + } + return numbers; + } + + // 128-bit representation + String get str128 { + if (bytes.length == 2) { + // 16-bit uuid + return '0000${_hexEncode(bytes)}-0000-1000-8000-00805f9b34fb' + .toLowerCase(); + } + if (bytes.length == 4) { + // 32-bit uuid + return '${_hexEncode(bytes)}-0000-1000-8000-00805f9b34fb'.toLowerCase(); + } + // 128-bit uuid + String one = _hexEncode(bytes.sublist(0, 4)); + String two = _hexEncode(bytes.sublist(4, 6)); + String three = _hexEncode(bytes.sublist(6, 8)); + String four = _hexEncode(bytes.sublist(8, 10)); + String five = _hexEncode(bytes.sublist(10, 16)); + return "$one-$two-$three-$four-$five".toLowerCase(); + } + + // shortest representation + String get str { + bool starts = str128.startsWith('0000'); + bool ends = str128.contains('-0000-1000-8000-00805f9b34fb'); + if (starts && ends) { + // 16-bit + return str128.substring(4, 8); + } + if (ends) { + // 32-bit + return str128.substring(0, 8); + } + // 128-bit + return str128; + } + + @override + String toString() => str; + + @override + operator ==(other) => other is Guid && hashCode == other.hashCode; + + @override + int get hashCode => str128.hashCode; + + @Deprecated('use str128 instead') + String get uuid128 => str128; + + @Deprecated('use str instead') + String get uuid => str; + + String _hexEncode(List numbers) { + return numbers + .map((n) => (n & 0xFF).toRadixString(16).padLeft(2, '0')) + .join(); + } +} diff --git a/lib/method_channel_midi_command.dart b/lib/method_channel_midi_command.dart index 8dddaf8..6f75837 100644 --- a/lib/method_channel_midi_command.dart +++ b/lib/method_channel_midi_command.dart @@ -27,6 +27,11 @@ class MethodChannelMidiCommand extends MidiCommandPlatform { map["type"], map["connected"] == "true"); dev.inputPorts = _portsFromDevice(map["inputs"], MidiPortType.IN); dev.outputPorts = _portsFromDevice(map["outputs"], MidiPortType.OUT); + dev.serviceUUIDs = (map["serviceUUIDs"] is List) + ? (map["serviceUUIDs"] as List) + .map((e) => Guid(e.toString())) + .toList() + : []; return dev; }).toList(); } diff --git a/lib/midi_device.dart b/lib/midi_device.dart index 62bd5fe..cd4215c 100644 --- a/lib/midi_device.dart +++ b/lib/midi_device.dart @@ -1,4 +1,7 @@ import 'package:flutter_midi_command_platform_interface/midi_port.dart'; +import 'package:flutter_midi_command_platform_interface/guid.dart'; + +export 'guid.dart'; class MidiDevice { String name; @@ -7,6 +10,7 @@ class MidiDevice { List inputPorts = []; List outputPorts = []; bool connected; + List serviceUUIDs = []; MidiDevice(this.id, this.name, this.type, this.connected);