syxpack/
lib.rs

1//! # syxpack
2//!
3//! `syxpack` is a collection of helpers for processing MIDI System Exclusive messages.
4
5use std::fmt;
6use std::collections::HashMap;
7use lazy_static::lazy_static;
8
9/// Manufacturer specific SysEx message initiator.
10pub const INITIATOR: u8 = 0xf0;
11
12/// Manufacturer specific SysEx message terminator.
13pub const TERMINATOR: u8 = 0xf7;
14
15/// Development/non-commercial SysEx manufacturer ID.
16pub const DEVELOPMENT: u8 = 0x7d;
17
18/// Universal non-real-time SysEx message indicator.
19pub const NON_REAL_TIME: u8 = 0x7e;
20
21/// Universal real-time SysEx message indicator.
22pub const REAL_TIME: u8 = 0x7f;
23
24/// Error type for System Exclusive messages.
25#[derive(Debug)]
26pub enum SystemExclusiveError {
27    InvalidMessage,
28    InvalidManufacturer,
29}
30
31impl fmt::Display for SystemExclusiveError {
32    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33        write!(f, "{}", match &self {
34            SystemExclusiveError::InvalidMessage => "Invalid System Exclusive message",
35            SystemExclusiveError::InvalidManufacturer => "Invalid manufacturer identifier"
36        })
37    }
38}
39
40/// MIDI manufacturer. The ID is either a single byte for standard IDs,
41/// or three bytes for extended IDs.
42#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
43pub enum Manufacturer {
44    Standard(u8),
45    Extended([u8; 3]),
46}
47
48impl Manufacturer {
49    /// Creates a new manufacturer from System Exclusive bytes.
50    pub fn from_bytes(data: &[u8]) -> Result<Self, SystemExclusiveError> {
51        if data.len() != 1 && data.len() != 3 {
52            return Err(SystemExclusiveError::InvalidManufacturer);
53        }
54        if data[0] == 0x00 {
55            Ok(Manufacturer::Extended([data[0], data[1], data[2]]))
56        }
57        else {
58            Ok(Manufacturer::Standard(data[0]))
59        }
60    }
61
62    /// Creates a new manufacturer with default ID.
63    pub fn new() -> Self {
64        Manufacturer::Standard(0x40)
65    }
66
67    /// Gets the manufacturer System Exclusive bytes.
68    pub fn to_bytes(&self) -> Vec<u8> {
69        match self {
70            Manufacturer::Standard(b) => vec![*b],
71            Manufacturer::Extended(bs) => vec![bs[0], bs[1], bs[2]],
72        }
73    }
74
75    /// Gets the manufacturer SysEx bytes as a hex string.
76    pub fn to_hex(&self) -> String {
77        hex::encode(self.to_bytes()).to_uppercase()
78    }
79
80    /// Returns `true` if this manufacturer represents development / non-commercial.
81    pub fn is_development(&self) -> bool {
82        match self {
83            Manufacturer::Standard(b) => *b == DEVELOPMENT,
84            Manufacturer::Extended(_) => false
85        }
86    }
87
88    /// Gets the name of this manufacturer.
89    pub fn name(&self) -> String {
90        if self.is_development() {
91            return "Development / Non-commercial".to_string()
92        }
93
94        let hex_id = self.to_hex();
95        if let Some(n) = MANUFACTURER_NAMES.get(&*hex_id) {
96            n.to_string()
97        }
98        else {
99            "Unknown manufacturer".to_string()
100        }
101    }
102
103    /// Gets the group of this manufacturer based on the identifier.
104    pub fn group(&self) -> ManufacturerGroup {
105        if self.is_development() {
106            return ManufacturerGroup::Development
107        }
108
109        match self {
110            Manufacturer::Standard(b) => {
111                if (0x01..0x40).contains(b) {
112                    ManufacturerGroup::NorthAmerican
113                }
114                else if (0x40..0x60).contains(b) {
115                    ManufacturerGroup::Japanese
116                }
117                else {
118                    ManufacturerGroup::EuropeanAndOther
119                }
120            },
121            Manufacturer::Extended(bs) => {
122                if (bs[1] & (1 << 6)) != 0 {  // 0x4x
123                    ManufacturerGroup::Japanese
124                }
125                else if (bs[1] & (1 << 5)) != 0 { // 0x2x
126                    ManufacturerGroup::EuropeanAndOther
127                }
128                else {
129                    ManufacturerGroup::NorthAmerican
130                }
131            }
132        }
133    }
134}
135
136impl fmt::Display for Manufacturer {
137    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138        write!(f, "{}", self.name())
139    }
140}
141
142/// Finds a manufacturer by initial match of name.
143pub fn find_manufacturer(name: &str) -> Result<Manufacturer, SystemExclusiveError> {
144    for (key, value) in &*MANUFACTURER_NAMES {
145        if value.to_lowercase().starts_with(&name.to_lowercase()) {
146            let id_bytes = hex::decode(key).unwrap();
147            return Ok(Manufacturer::from_bytes(&id_bytes).unwrap());
148        }
149    }
150    return Err(SystemExclusiveError::InvalidManufacturer);
151}
152
153/// The kind of a Universal System Exclusive message.
154#[derive(Debug)]
155pub enum UniversalKind {
156    NonRealTime,
157    RealTime,
158}
159
160impl fmt::Display for UniversalKind {
161    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162        let name = match self {
163            UniversalKind::NonRealTime => "Non-Real-time",
164            UniversalKind::RealTime => "Real-time",
165        };
166        write!(f, "{}", name)
167    }
168}
169
170/// A MIDI System Exclusive message.
171#[derive(Debug)]
172pub enum Message {
173    Universal { kind: UniversalKind, target: u8, sub_id1: u8, sub_id2: u8, payload: Vec<u8> },
174    ManufacturerSpecific { manufacturer: Manufacturer, payload: Vec<u8> },
175}
176
177/// Returns the number of System Exclusive messages in this vector,
178/// based on the count of terminator bytes.
179pub fn message_count(data: &Vec<u8>) -> usize {
180    data.iter().filter(|&n| *n == TERMINATOR).count()
181}
182
183/// Splits the vector by the terminator byte, including it.
184pub fn split_messages(data: Vec<u8>) -> Vec<Vec<u8>> {
185    let mut parts: Vec<Vec<u8>> = Vec::new();
186    for part in data.split_inclusive(|&n| n == TERMINATOR) {
187        parts.push(part.to_vec());
188    }
189    parts
190}
191
192impl Message {
193    /// Creates a new SysEx message based on the initial data bytes.
194    pub fn from_bytes(data: &[u8]) -> Result<Self, SystemExclusiveError> {
195        if data[0] != INITIATOR {
196            return Err(SystemExclusiveError::InvalidMessage);
197        }
198
199        let last_byte_index = data.len() - 1;
200        if data[last_byte_index] != TERMINATOR {
201            return Err(SystemExclusiveError::InvalidMessage);
202        }
203
204        if data.len() < 5 {   // too short
205            return Err(SystemExclusiveError::InvalidMessage);
206        }
207
208        match data[1] {
209            DEVELOPMENT => Ok(Message::ManufacturerSpecific {
210                manufacturer: Manufacturer::Standard(data[1]),
211                payload: data[2..last_byte_index].to_vec()
212            }),
213            NON_REAL_TIME => Ok(Message::Universal {
214                kind: UniversalKind::NonRealTime,
215                target: data[2],
216                sub_id1: data[3],
217                sub_id2: data[4],
218                payload: data[5..last_byte_index].to_vec()
219            }),
220            REAL_TIME => Ok(Message::Universal {
221                kind: UniversalKind::RealTime,
222                target: data[2],
223                sub_id1: data[3],
224                sub_id2: data[4],
225                payload: data[5..last_byte_index].to_vec()
226            }),
227            0x00 => Ok(Message::ManufacturerSpecific {
228                manufacturer: Manufacturer::Extended([data[1], data[2], data[3]]),
229                payload: data[4..last_byte_index].to_vec()
230            }),
231            _ => Ok(Message::ManufacturerSpecific {
232                manufacturer: Manufacturer::Standard(data[1]),
233                payload: data[2..last_byte_index].to_vec()
234            }),
235        }
236    }
237
238    /// Converts the message into bytes for MIDI messaging.
239    pub fn to_bytes(&self) -> Vec<u8> {
240        let mut result = Vec::<u8>::new();
241
242        match self {
243            Message::Universal { kind, target, sub_id1, sub_id2, payload } => {
244                result.push(INITIATOR);
245                result.push(match kind {
246                    UniversalKind::NonRealTime => NON_REAL_TIME,
247                    UniversalKind::RealTime => REAL_TIME,
248                });
249                result.push(*target);
250                result.push(*sub_id1);
251                result.push(*sub_id2);
252                result.extend(payload);
253                result.push(TERMINATOR);
254            },
255            Message::ManufacturerSpecific { manufacturer, payload } => {
256                result.push(INITIATOR);
257                result.extend(manufacturer.to_bytes());
258                result.extend(payload);
259                result.push(TERMINATOR);
260            }
261        }
262
263        result
264    }
265
266    /// Compute the MD5 digest for this message.
267    pub fn digest(&self) -> md5::Digest {
268        md5::compute(self.to_bytes())
269    }
270}
271
272/// Group of manufacturer.
273#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
274pub enum ManufacturerGroup {
275    Development,
276    NorthAmerican,
277    EuropeanAndOther,
278    Japanese,
279}
280
281impl fmt::Display for ManufacturerGroup {
282    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
283        let name = match self {
284            ManufacturerGroup::Development => "Development",
285            ManufacturerGroup::EuropeanAndOther => "European & Other",
286            ManufacturerGroup::Japanese => "Japanese",
287            ManufacturerGroup::NorthAmerican => "North American",
288        };
289        write!(f, "{}", name)
290    }
291}
292
293lazy_static! {
294    static ref MANUFACTURER_NAMES: HashMap<&'static str, &'static str> = {
295        HashMap::from([
296            ("01", "Sequential Circuits"),
297            ("02", "IDP"),
298            ("03", "Voyetra Turtle Beach, Inc."),
299            ("04", "Moog Music"),
300            ("05", "Passport Designs"),
301            ("06", "Lexicon Inc."),
302            ("07", "Kurzweil / Young Chang"),
303            ("08", "Fender"),
304            ("09", "MIDI9"),
305            ("0A", "AKG Acoustics"),
306            ("0B", "Voyce Music"),
307            ("0C", "WaveFrame (Timeline)"),
308            ("0D", "ADA Signal Processors, Inc."),
309            ("0E", "Garfield Electronics"),
310            ("0F", "Ensoniq"),
311            ("10", "Oberheim / Gibson Labs"),
312            ("11", "Apple"),
313            ("12", "Grey Matter Response"),
314            ("13", "Digidesign Inc."),
315            ("14", "Palmtree Instruments"),
316            ("15", "JLCooper Electronics"),
317            ("16", "Lowrey Organ Company"),
318            ("17", "Adams-Smith"),
319            ("18", "E-mu"),
320            ("19", "Harmony Systems"),
321            ("1A", "ART"),
322            ("1B", "Baldwin"),
323            ("1C", "Eventide"),
324            ("1D", "Inventronics"),
325            ("1E", "Key Concepts"),
326            ("1F", "Clarity"),
327            ("20", "Passac"),
328            ("21", "Proel Labs (SIEL)"),
329            ("22", "Synthaxe (UK)"),
330            ("23", "Stepp"),
331            ("24", "Hohner"),
332            ("25", "Twister"),
333            ("26", "Ketron s.r.l."),
334            ("27", "Jellinghaus MS"),
335            ("28", "Southworth Music Systems"),
336            ("29", "PPG (Germany)"),
337            ("2A", "JEN"),
338            ("2B", "Solid State Logic Organ Systems"),
339            ("2C", "Audio Veritrieb-P. Struven"),
340            ("2D", "Neve"),
341            ("2E", "Soundtracs Ltd."),
342            ("2F", "Elka"),
343            ("30", "Dynacord"),
344            ("31", "Viscount International Spa (Intercontinental Electronics)"),
345            ("32", "Drawmer"),
346            ("33", "Clavia Digital Instruments"),
347            ("34", "Audio Architecture"),
348            ("35", "Generalmusic Corp SpA"),
349            ("36", "Cheetah Marketing"),
350            ("37", "C.T.M."),
351            ("38", "Simmons UK"),
352            ("39", "Soundcraft Electronics"),
353            ("3A", "Steinberg Media Technologies GmbH"),
354            ("3B", "Wersi Gmbh"),
355            ("3C", "AVAB Niethammer AB"),
356            ("3D", "Digigram"),
357            ("3E", "Waldorf Electronics GmbH"),
358            ("3F", "Quasimidi"),
359
360            ("000001", "Time/Warner Interactive"),
361            ("000002", "Advanced Gravis Comp. Tech Ltd."),
362            ("000003", "Media Vision"),
363            ("000004", "Dornes Research Group"),
364            ("000005", "K-Muse"),
365            ("000006", "Stypher"),
366            ("000007", "Digital Music Corp."),
367            ("000008", "IOTA Systems"),
368            ("000009", "New England Digital"),
369            ("00000A", "Artisyn"),
370            ("00000B", "IVL Technologies Ltd."),
371            ("00000C", "Southern Music Systems"),
372            ("00000D", "Lake Butler Sound Company"),
373            ("00000E", "Alesis Studio Electronics"),
374            ("00000F", "Sound Creation"),
375            ("000010", "DOD Electronics Corp."),
376            ("000011", "Studer-Editech"),
377            ("000012", "Sonus"),
378            ("000013", "Temporal Acuity Products"),
379            ("000014", "Perfect Fretworks"),
380            ("000015", "KAT Inc."),
381            ("000016", "Opcode Systems"),
382            ("000017", "Rane Corporation"),
383            ("000018", "Anadi Electronique"),
384            ("000019", "KMX"),
385            ("00001A", "Allen & Heath Brenell"),
386            ("00001B", "Peavey Electronics"),
387            ("00001C", "360 Systems"),
388            ("00001D", "Spectrum Design and Development"),
389            ("00001E", "Marquis Music"),
390            ("00001F", "Zeta Systems"),
391            ("000020", "Axxes (Brian Parsonett)"),
392            ("000021", "Orban"),
393            ("000022", "Indian Valley Mfg."),
394            ("000023", "Triton"),
395            ("000024", "KTI"),
396            ("000025", "Breakway Technologies"),
397            ("000026", "Leprecon / CAE Inc."),
398            ("000027", "Harrison Systems Inc."),
399            ("000028", "Future Lab/Mark Kuo"),
400            ("000029", "Rocktron Corporation"),
401            ("00002A", "PianoDisc"),
402            ("00002B", "Cannon Research Group"),
403            ("00002C", "Reserved"),
404            ("00002D", "Rodgers Instrument LLC"),
405            ("00002E", "Blue Sky Logic"),
406            ("00002F", "Encore Electronics"),
407            ("000030", "Uptown"),
408            ("000031", "Voce"),
409            ("000032", "CTI Audio, Inc. (Musically Intel. Devs.)"),
410            ("000033", "S3 Incorporated"),
411            ("000034", "Broderbund / Red Orb"),
412            ("000035", "Allen Organ Co."),
413            ("000036", "Reserved"),
414            ("000037", "Music Quest"),
415            ("000038", "Aphex"),
416            ("000039", "Gallien Krueger"),
417            ("00003A", "IBM"),
418            ("00003B", "Mark Of The Unicorn"),
419            ("00003C", "Hotz Corporation"),
420            ("00003D", "ETA Lighting"),
421            ("00003E", "NSI Corporation"),
422            ("00003F", "Ad Lib, Inc."),
423            ("000040", "Richmond Sound Design"),
424            ("000041", "Microsoft"),
425            ("000042", "Mindscape (Software Toolworks)"),
426            ("000043", "Russ Jones Marketing / Niche"),
427            ("000044", "Intone"),
428            ("000045", "Advanced Remote Technologies"),
429            ("000046", "White Instruments"),
430            ("000047", "GT Electronics/Groove Tubes"),
431            ("000048", "Pacific Research & Engineering"),
432            ("000049", "Timeline Vista, Inc."),
433            ("00004A", "Mesa Boogie Ltd."),
434            ("00004B", "FSLI"),
435            ("00004C", "Sequoia Development Group"),
436            ("00004D", "Studio Electronics"),
437            ("00004E", "Euphonix, Inc"),
438            ("00004F", "InterMIDI, Inc."),
439            ("000050", "MIDI Solutions Inc."),
440            ("000051", "3DO Company"),
441            ("000052", "Lightwave Research / High End Systems"),
442            ("000053", "Micro-W Corporation"),
443            ("000054", "Spectral Synthesis, Inc."),
444            ("000055", "Lone Wolf"),
445            ("000056", "Studio Technologies Inc."),
446            ("000057", "Peterson Electro-Musical Product, Inc."),
447            ("000058", "Atari Corporation"),
448            ("000059", "Marion Systems Corporation"),
449            ("00005A", "Design Event"),
450            ("00005B", "Winjammer Software Ltd."),
451            ("00005C", "AT&T Bell Laboratories"),
452            ("00005D", "Reserved"),
453            ("00005E", "Symetrix"),
454            ("00005F", "MIDI the World"),
455            ("000060", "Spatializer"),
456            ("000061", "Micros ‘N MIDI"),
457            ("000062", "Accordians International"),
458            ("000063", "EuPhonics (now 3Com)"),
459            ("000064", "Musonix"),
460            ("000065", "Turtle Beach Systems (Voyetra)"),
461            ("000066", "Loud Technologies / Mackie"),
462            ("000067", "Compuserve"),
463            ("000068", "BEC Technologies"),
464            ("000069", "QRS Music Inc"),
465            ("00006A", "P.G. Music"),
466            ("00006B", "Sierra Semiconductor"),
467            ("00006C", "EpiGraf"),
468            ("00006D", "Electronics Diversified Inc"),
469            ("00006E", "Tune 1000"),
470            ("00006F", "Advanced Micro Devices"),
471            ("000070", "Mediamation"),
472            ("000071", "Sabine Musical Mfg. Co. Inc."),
473            ("000072", "Woog Labs"),
474            ("000073", "Micropolis Corp"),
475            ("000074", "Ta Horng Musical Instrument"),
476            ("000075", "e-Tek Labs (Forte Tech)"),
477            ("000076", "Electro-Voice"),
478            ("000077", "Midisoft Corporation"),
479            ("000078", "QSound Labs"),
480            ("000079", "Westrex"),
481            ("00007A", "Nvidia"),
482            ("00007B", "ESS Technology"),
483            ("00007C", "Media Trix Peripherals"),
484            ("00007D", "Brooktree Corp"),
485            ("00007E", "Otari Corp"),
486            ("00007F", "Key Electronics, Inc."),
487            ("000100", "Shure Incorporated"),
488            ("000101", "AuraSound"),
489            ("000102", "Crystal Semiconductor"),
490            ("000103", "Conexant (Rockwell)"),
491            ("000104", "Silicon Graphics"),
492            ("000105", "M-Audio (Midiman)"),
493            ("000106", "PreSonus"),
494            // 000107?
495            ("000108", "Topaz Enterprises"),
496            ("000109", "Cast Lighting"),
497            ("00010A", "Microsoft Consumer Division"),
498            ("00010B", "Sonic Foundry"),
499            ("00010C", "Line 6 (Fast Forward) (Yamaha)"),
500            ("00010D", "Beatnik Inc"),
501            ("00010E", "Van Koevering Company"),
502            ("00010F", "Altech Systems"),
503            ("000110", "S & S Research"),
504            ("000111", "VLSI Technology"),
505            ("000112", "Chromatic Research"),
506            ("000113", "Sapphire"),
507            ("000114", "IDRC"),
508            ("000115", "Justonic Tuning"),
509            ("000116", "TorComp Research Inc."),
510            ("000117", "Newtek Inc."),
511            ("000118", "Sound Sculpture"),
512            ("000119", "Walker Technical"),
513            ("00011A", "Digital Harmony (PAVO)"),
514            ("00011B", "InVision Interactive"),
515            ("00011C", "T-Square Design"),
516            ("00011D", "Nemesys Music Technology"),
517            ("00011E", "DBX Professional (Harman Intl)"),
518            ("00011F", "Syndyne Corporation"),
519            ("000120", "Bitheadz"),
520            ("000121", "BandLab Technologies"),
521            ("000122", "Analog Devices"),
522            ("000123", "National Semiconductor"),
523            ("000124", "Boom Theory / Adinolfi Alternative Percussion"),
524            ("000125", "Virtual DSP Corporation"),
525            ("000126", "Antares Systems"),
526            ("000127", "Angel Software"),
527            ("000128", "St Louis Music"),
528            ("000129", "Passport Music Software LLC (Gvox)"),
529            ("00012A", "Ashley Audio Inc."),
530            ("00012B", "Vari-Lite Inc."),
531            ("00012C", "Summit Audio Inc."),
532            ("00012D", "Aureal Semiconductor Inc."),
533            ("00012E", "SeaSound LLC"),
534            ("00012F", "U.S. Robotics"),
535            ("000130", "Aurisis Research"),
536            ("000131", "Nearfield Research"),
537            ("000132", "FM7 Inc"),
538            ("000133", "Swivel Systems"),
539            ("000134", "Hyperactive Audio Systems"),
540            ("000135", "MidiLite (Castle Studios Productions)"),
541            ("000136", "Radikal Technologies"),
542            ("000137", "Roger Linn Design"),
543            ("000138", "TC-Helicon Vocal Technologies"),
544            ("000139", "Event Electronics"),
545            ("00013A", "Sonic Network Inc"),
546            ("00013B", "Realtime Music Solutions"),
547            ("00013C", "Apogee Digital"),
548            ("00013D", "Classical Organs, Inc."),
549            ("00013E", "Microtools Inc."),
550            ("00013F", "Numark Industries"),
551            ("000140", "Frontier Design Group, LLC"),
552            ("000141", "Recordare LLC"),
553            ("000142", "Starr Labs"),
554            ("000143", "Voyager Sound Inc."),
555            ("000144", "Manifold Labs"),
556            ("000145", "Aviom Inc."),
557            ("000146", "Mixmeister Technology"),
558            ("000147", "Notation Software"),
559            ("000148", "Mercurial Communications"),
560            ("000149", "Wave Arts"),
561            ("00014A", "Logic Sequencing Devices"),
562            ("00014B", "Axess Electronics"),
563            ("00014C", "Muse Research"),
564            ("00014D", "Open Labs"),
565            ("00014E", "Guillemot Corp"),
566            ("00014F", "Samson Technologies"),
567            ("000150", "Electronic Theatre Controls"),
568            ("000151", "Blackberry (RIM)"),
569            ("000152", "Mobileer"),
570            ("000153", "Synthogy"),
571            ("000154", "Lynx Studio Technology Inc."),
572            ("000155", "Damage Control Engineering LLC"),
573            ("000156", "Yost Engineering, Inc."),
574            ("000157", "Brooks & Forsman Designs LLC / DrumLite"),
575            ("000158", "Infinite Response"),
576            ("000159", "Garritan Corp"),
577            ("00015A", "Plogue Art et Technologie, Inc"),
578            ("00015B", "RJM Music Technology"),
579            ("00015C", "Custom Solutions Software"),
580            ("00015D", "Sonarcana LLC / Highly Liquid"),
581            ("00015E", "Centrance"),
582            ("00015F", "Kesumo LLC"),
583            ("000160", "Stanton (Gibson Brands)"),
584            ("000161", "Livid Instruments"),
585            ("000162", "First Act / 745 Media"),
586            ("000163", "Pygraphics, Inc."),
587            ("000164", "Panadigm Innovations Ltd"),
588            ("000165", "Avedis Zildjian Co"),
589            ("000166", "Auvital Music Corp"),
590            ("000167", "You Rock Guitar (was: Inspired Instruments)"),
591            ("000168", "Chris Grigg Designs"),
592            ("000169", "Slate Digital LLC"),
593            ("00016A", "Mixware"),
594            ("00016B", "Social Entropy"),
595            ("00016C", "Source Audio LLC"),
596            ("00016D", "Ernie Ball / Music Man"),
597            ("00016E", "Fishman"),
598            ("00016F", "Custom Audio Electronics"),
599            ("000170", "American Audio/DJ"),
600            ("000171", "Mega Control Systems"),
601            ("000172", "Kilpatrick Audio"),
602            ("000173", "iConnectivity"),
603            ("000174", "Fractal Audio"),
604            ("000175", "NetLogic Microsystems"),
605            ("000176", "Music Computing"),
606            ("000177", "Nektar Technology Inc"),
607            ("000178", "Zenph Sound Innovations"),
608            ("000179", "DJTechTools.com"),
609            ("00017A", "Rezonance Labs"),
610            ("00017B", "Decibel Eleven"),
611            ("00017C", "CNMAT"),
612            ("00017D", "Media Overkill"),
613            ("00017E", "Confusion Studios"),
614            ("00017F", "moForte Inc"),
615            ("000200", "Miselu Inc"),
616            ("000201", "Amelia's Compass LLC"),
617            ("000202", "Zivix LLC"),
618            ("000203", "Artiphon"),
619            ("000204", "Synclavier Digital"),
620            ("000205", "Light & Sound Control Devices LLC"),
621            ("000206", "Retronyms Inc"),
622            ("000207", "JS Technologies"),
623            ("000208", "Quicco Sound"),
624            ("000209", "A-Designs Audio"),
625            ("00020A", "McCarthy Music Corp"),
626            ("00020B", "Denon DJ"),
627            ("00020C", "Keith Robert Murray"),
628            ("00020D", "Google"),
629            ("00020E", "ISP Technologies"),
630            ("00020F", "Abstrakt Instruments LLC"),
631            ("000210", "Meris LLC"),
632            ("000211", "Sensorpoint LLC"),
633            ("000212", "Hi-Z Labs"),
634            ("000213", "Imitone"),
635            ("000214", "Intellijel Designs Inc."),
636            ("000215", "Dasz Instruments Inc."),
637            ("000216", "Remidi"),
638            ("000217", "Disaster Area Designs LLC"),
639            ("000218", "Universal Audio"),
640            ("000219", "Carter Duncan Corp"),
641            ("00021A", "Essential Technology"),
642            ("00021B", "Cantux Research LLC"),
643            ("00021C", "Hummel Technologies"),
644            ("00021D", "Sensel Inc"),
645            ("00021E", "DBML Group"),
646            ("00021F", "Madrona Labs"),
647            ("000220", "Mesa Boogie"),
648            ("000221", "Effigy Labs"),
649            ("000222", "Amenote"),
650            ("000223", "Red Panda LLC"),
651            ("000224", "OnSong LLC"),
652            ("000225", "Jamboxx Inc."),
653            ("000226", "Electro-Harmonix"),
654            ("000227", "RnD64 Inc"),
655            ("000228", "Neunaber Technology LLC"),
656            ("000229", "Kaom Inc."),
657            ("00022A", "Hallowell EMC"),
658            ("00022B", "Sound Devices, LLC"),
659            ("00022C", "Spectrasonics, Inc"),
660            ("00022D", "Second Sound, LLC"),
661            ("00022E", "8eo (Horn)"),
662            ("00022F", "VIDVOX LLC"),
663            ("000230", "Matthews Effects"),
664            ("000231", "Bright Blue Beetle"),
665            ("000232", "Audio Impressions"),
666            ("000233", " Looperlative"),
667            ("000234", "Steinway"),
668            ("000235", "Ingenious Arts and Technologies LLC"),
669            ("000236", "DCA Audio"),
670            ("000237", "Buchla USA"),
671            ("000238", "Sinicon"),
672            ("000239", "Isla Instruments"),
673            ("00023A", "Soundiron LLC"),
674            ("00023B", "Sonoclast, LLC"),
675            ("00023C", "Copper and Cedar"),
676            ("00023D", "Whirled Notes"),
677            ("00023E", "Cejetvole, LLC"),
678            ("00023F", "DAWn Audio LLC"),
679            ("000240", "Space Brain Circuits"),
680            ("000241", "Caedence"),
681            ("000242", "HCN Designs, LLC (The MIDI Maker)"),
682            ("000243", "PTZOptics"),
683            ("000244", "Noise Engineering"),
684            ("000245", "Synthesia LLC"),
685            ("000246", "Jeff Whitehead Lutherie LLC"),
686            ("000247", "Wampler Pedals Inc."),
687            ("000248", "Tapis Magique"),
688            ("000249", "Leaf Secrets"),
689            ("00024A", "Groove Synthesis"),
690            ("00024B", "Audiocipher Technologies LLC"),
691            ("00024C", "Mellotron Inc."),
692            ("00024D", "Hologram Electronics LLC"),
693            ("00024E", "iCON Americas, LLC"),
694            ("00024F", "Singular Sound"),
695            ("000250", "Genovation Inc"),
696            ("000251", "Method Red"),
697            ("000252", "Brain Inventions"),
698            ("000253", "Synervoz Communications Inc."),
699            ("000254", "Hypertriangle Inc"),
700
701            // European & Other Group
702            ("002000", "Dream SAS"),
703            ("002001", "Strand Lighting"),
704            ("002002", "Amek Div of Harman Industries"),
705            ("002003", "Casa Di Risparmio Di Loreto"),
706            ("002004", "Böhm electronic GmbH"),
707            ("002005", "Syntec Digital Audio"),
708            ("002006", "Trident Audio Developments"),
709            ("002007", "Real World Studio"),
710            ("002008", "Evolution Synthesis, Ltd"),
711            ("002009", "Yes Technology"),
712            ("00200A", "Audiomatica"),
713            ("00200B", "Bontempi SpA (Sigma)"),
714            ("00200C", "F.B.T. Elettronica SpA"),
715            ("00200D", "MidiTemp GmbH"),
716            ("00200E", "LA Audio (Larking Audio)"),
717            ("00200F", "Zero 88 Lighting Limited"),
718            ("002010", "Micon Audio Electronics GmbH"),
719            ("002011", "Forefront Technology"),
720            ("002012", "Studio Audio and Video Ltd."),
721            ("002013", "Kenton Electronics"),
722            ("002014", "Celco/ Electrosonic"),
723            ("002015", "ADB"),
724            ("002016", "Marshall Products Limited"),
725            ("002017", "DDA"),
726            ("002018", "BSS Audio Ltd."),
727            ("002019", "MA Lighting Technology"),
728            ("00201A", "Fatar SRL c/o Music Industries"),
729            ("00201B", "QSC Audio Products Inc."),
730            ("00201C", "Artisan Clasic Organ Inc."),
731            ("00201D", "Orla Spa"),
732            ("00201E", "Pinnacle Audio (Klark Teknik PLC)"),
733            ("00201F", "TC Electronics"),
734            ("002020", "Doepfer Musikelektronik GmbH"),
735            ("002021", "Creative ATC / E-mu"),
736            ("002022", "Seyddo/Minami"),
737            ("002023", "LG Electronics (Goldstar)"),
738            ("002024", "Midisoft sas di M.Cima & C"),
739            ("002025", "Samick Musical Inst. Co. Ltd."),
740            ("002026", "Penny and Giles (Bowthorpe PLC)"),
741            ("002027", "Acorn Computer"),
742            ("002028", "LSC Electronics Pty. Ltd."),
743            ("002029", "Focusrite/Novation"),
744            ("00202A", "Samkyung Mechatronics"),
745            ("00202B", "Medeli Electronics Co."),
746            ("00202C", "Charlie Lab SRL"),
747            ("00202D", "Blue Chip Music Technology"),
748            ("00202E", "BEE OH Corp"),
749            ("00202F", "LG Semicon America"),
750            ("002030", "TESI"),
751            ("002031", "EMAGIC"),
752            ("002032", "Behringer GmbH"),
753            ("002033", "Access Music Electronics"),
754            ("002034", "Synoptic"),
755            ("002035", "Hanmesoft"),
756            ("002036", "Terratec Electronic GmbH"),
757            ("002037", "Proel SpA"),
758            ("002038", "IBK MIDI"),
759            ("002039", "IRCAM"),
760            ("00203A", "Propellerhead Software"),
761            ("00203B", "Red Sound Systems Ltd"),
762            ("00203C", "Elektron ESI AB"),
763            ("00203D", "Sintefex Audio"),
764            ("00203E", "MAM (Music and More)"),
765            ("00203F", "Amsaro GmbH"),
766            ("002040", "CDS Advanced Technology BV (Lanbox)"),
767            ("002041", "Mode Machines (Touched By Sound GmbH)"),
768            ("002042", "DSP Arts"),
769            ("002043", "Phil Rees Music Tech"),
770            ("002044", "Stamer Musikanlagen GmbH"),
771            ("002045", "Musical Muntaner S.A. dba Soundart"),
772            ("002046", "C-Mexx Software"),
773
774            ("00206B", "Arturia"),
775            ("002076", "Teenage Engineering"),
776
777            ("002103", "PreSonus Software Ltd"),
778
779            ("002109", "Native Instruments"),
780
781            ("002110", "ROLI Ltd"),
782
783            ("00211A", "IK Multimedia"),
784
785            ("00211D", "Ableton"),
786
787            ("40", "Kawai Musical Instruments MFG. CO. Ltd"),
788            ("41", "Roland Corporation"),
789            ("42", "Korg Inc."),
790            ("43", "Yamaha"),
791            ("44", "Casio Computer Co. Ltd"),
792            // 0x45 is not assigned
793            ("46", "Kamiya Studio Co. Ltd"),
794            ("47", "Akai Electric Co. Ltd."),
795            ("48", "Victor Company of Japan, Ltd."),
796            ("4B", "Fujitsu Limited"),
797            ("4C", "Sony Corporation"),
798            ("4E", "Teac Corporation"),
799            ("50", "Matsushita Electric Industrial Co. , Ltd"),
800            ("51", "Fostex Corporation"),
801            ("52", "Zoom Corporation"),
802            ("54", "Matsushita Communication Industrial Co., Ltd."),
803            ("55", "Suzuki Musical Instruments MFG. Co., Ltd."),
804            ("56", "Fuji Sound Corporation Ltd."),
805            ("57", "Acoustic Technical Laboratory, Inc."),
806            // 58h is not assigned
807            ("59", "Faith, Inc."),
808            ("5A", "Internet Corporation"),
809            // 5Bh is not assigned
810            ("5C", "Seekers Co. Ltd."),
811            // 5Dh and 5Eh are not assigned
812            ("5F", "SD Card Association"),
813
814            ("004000", "Crimson Technology Inc."),
815            ("004001", "Softbank Mobile Corp"),
816            ("004003", "D&M Holdings Inc."),
817            ("004004", "Xing Inc."),
818            ("004005", "Alpha Theta Corporation"),
819            ("004006", "Pioneer Corporation"),
820            ("004007", "Slik Corporation"),
821        ])
822    };
823}
824
825#[cfg(test)]
826mod tests {
827    use super::*;
828
829    #[test]
830    fn new_message_manufacturer_standard() {
831        let data = vec![0xF0, 0x40, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3F, 0xF7];
832        let message = Message::from_bytes(&data);
833        if let Ok(Message::ManufacturerSpecific { manufacturer, .. }) = message {
834            assert_eq!(manufacturer, Manufacturer::Standard(0x40));
835        }
836        else {
837            panic!("Expected a manufacturer-specific message with standard identifier");
838        }
839    }
840
841    #[test]
842    fn new_message_manufacturer_extended() {
843        let data = vec![0xF0, 0x00, 0x00, 0x0E, 0x00, 0x41, 0x63, 0x00, 0x5D, 0xF7];
844        let message = Message::from_bytes(&data);
845        if let Ok(Message::ManufacturerSpecific { manufacturer, .. }) = message {
846            assert_eq!(manufacturer, Manufacturer::Extended([0x00, 0x00, 0x0E]));
847        }
848        else {
849            panic!("Expected a manufacturer-specific message with extended identifier");
850        }
851    }
852
853    #[test]
854    fn manufacturer_message() {
855        let message = Message::ManufacturerSpecific {
856            manufacturer: Manufacturer::Standard(0x40),  // Kawai ID
857            payload: vec![
858                0x00, // MIDI channel 1
859                0x20, // one block data dump
860                0x00, // "synthesizer group"
861                0x04, // K4/K4r ID no.
862                0x00, // internal patch
863                0x3F, // patch slot D-16
864            ],
865        };
866        let message_bytes = message.to_bytes();
867        assert_eq!(message_bytes, vec![0xF0, 0x40, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3F, 0xF7]);
868    }
869
870    #[test]
871    fn standard_manufacturer() {
872        let message = Message::ManufacturerSpecific {
873            manufacturer: Manufacturer::Standard(0x43),
874            payload: vec![],
875        };
876        let message_bytes = message.to_bytes();
877        assert_eq!(message_bytes, vec![0xF0, 0x43, 0xF7]);
878    }
879
880    #[test]
881    fn extended_manufacturer() {
882        let message = Message::ManufacturerSpecific {
883            manufacturer: Manufacturer::Extended([0x00, 0x00, 0x01]),
884            payload: vec![],
885        };
886        let message_bytes = message.to_bytes();
887        assert_eq!(message_bytes, vec![0xF0, 0x00, 0x00, 0x01, 0xF7]);
888    }
889
890    #[test]
891    fn universal() {
892        let message = Message::Universal {
893            kind: UniversalKind::NonRealTime,
894            target: 0x00,
895            sub_id1: 0x06,  // General information
896            sub_id2: 0x01,  // - Identity request
897            payload: vec![]
898        };
899        let message_bytes = message.to_bytes();
900        assert_eq!(message_bytes, vec![INITIATOR, NON_REAL_TIME, 0x00, 0x06, 0x01, TERMINATOR]);
901    }
902
903    #[test]
904    fn development_manufacturer() {
905        let message = Message::ManufacturerSpecific {
906            manufacturer: Manufacturer::Standard(DEVELOPMENT),
907            payload: vec![],
908        };
909        let message_bytes = message.to_bytes();
910        assert_eq!(message_bytes, vec![INITIATOR, DEVELOPMENT, TERMINATOR]);
911    }
912
913    #[test]
914    fn manufacturer_display_name() {
915        let manufacturer = Manufacturer::Standard(0x43);
916        assert_eq!(format!("{}", manufacturer), "Yamaha");
917    }
918
919    #[test]
920    fn find_manufacturer_name_success() {
921        let manuf = find_manufacturer("yama").unwrap();
922        assert_eq!(manuf.name(), "Yamaha");
923    }
924
925    #[test]
926    fn find_manufacturer_name_failure() {
927        assert!(find_manufacturer("humppaurku").is_err());
928    }
929}