1 /*
2  * libOPNMIDI is a free Software MIDI synthesizer library with OPN2 (YM2612) emulation
3  *
4  * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
5  * OPNMIDI Library and YM2612 support:   Copyright (c) 2017-2020 Vitaly Novichkov <admin@wohlnet.ru>
6  *
7  * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
8  * http://iki.fi/bisqwit/source/adlmidi.html
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #ifndef OPNMIDI_MIDIPLAY_HPP
25 #define OPNMIDI_MIDIPLAY_HPP
26 
27 #include "opnbank.h"
28 #include "opnmidi_private.hpp"
29 #include "opnmidi_ptr.hpp"
30 #include "structures/pl_list.hpp"
31 
32 /**
33  * @brief Hooks of the internal events
34  */
35 struct MIDIEventHooks
36 {
MIDIEventHooksMIDIEventHooks37     MIDIEventHooks() :
38         onNote(NULL),
39         onNote_userData(NULL),
40         onDebugMessage(NULL),
41         onDebugMessage_userData(NULL)
42     {}
43 
44     //! Note on/off hooks
45     typedef void (*NoteHook)(void *userdata, int adlchn, int note, int ins, int pressure, double bend);
46     NoteHook     onNote;
47     void         *onNote_userData;
48 
49     //! Library internal debug messages
50     typedef void (*DebugMessageHook)(void *userdata, const char *fmt, ...);
51     DebugMessageHook onDebugMessage;
52     void *onDebugMessage_userData;
53 };
54 
55 class OPNMIDIplay
56 {
57     friend void opn2_reset(struct OPN2_MIDIPlayer*);
58 public:
59     explicit OPNMIDIplay(unsigned long sampleRate = 22050);
60     ~OPNMIDIplay();
61 
62     void applySetup();
63 
64     void partialReset();
65     void resetMIDI();
66 
67 private:
68     void resetMIDIDefaults(int offset = 0);
69 
70 public:
71     /**********************Internal structures and classes**********************/
72 
73     /**
74      * @brief Persistent settings for each MIDI channel
75      */
76     struct MIDIchannel
77     {
78         //! Default MIDI volume
79         uint8_t def_volume;
80         //! Default LSB of a bend sensitivity
81         int     def_bendsense_lsb;
82         //! Default MSB of a bend sensitivity
83         int     def_bendsense_msb;
84 
85         //! LSB Bank number
86         uint8_t bank_lsb,
87         //! MSB Bank number
88                 bank_msb;
89         //! Current patch number
90         uint8_t patch;
91         //! Volume level
92         uint8_t volume,
93         //! Expression level
94                 expression;
95         //! Panning level
96         uint8_t panning,
97         //! Vibrato level
98                 vibrato,
99         //! Channel aftertouch level
100                 aftertouch;
101         //! Portamento time
102         uint16_t portamento;
103         //! Is Pedal sustain active
104         bool sustain;
105         //! Is Soft pedal active
106         bool softPedal;
107         //! Is portamento enabled
108         bool portamentoEnable;
109         //! Source note number used by portamento
110         int8_t portamentoSource;  // note number or -1
111         //! Portamento rate
112         double portamentoRate;
113         //! Per note Aftertouch values
114         uint8_t noteAftertouch[128];
115         //! Is note aftertouch has any non-zero value
116         bool    noteAfterTouchInUse;
117         //! Reserved
118         char _padding[6];
119         //! Pitch bend value
120         int bend;
121         //! Pitch bend sensitivity
122         double bendsense;
123         //! Pitch bend sensitivity LSB value
124         int bendsense_lsb,
125         //! Pitch bend sensitivity MSB value
126             bendsense_msb;
127         //! Vibrato position value
128         double  vibpos,
129         //! Vibrato speed value
130                 vibspeed,
131         //! Vibrato depth value
132                 vibdepth;
133         //! Vibrato delay time
134         int64_t vibdelay_us;
135         //! Last LSB part of RPN value received
136         uint8_t lastlrpn,
137         //! Last MSB poart of RPN value received
138                 lastmrpn;
139         //! Interpret RPN value as NRPN
140         bool nrpn;
141         //! Brightness level
142         uint8_t brightness;
143 
144         //! Is melodic channel turned into percussion
145         bool is_xg_percussion;
146 
147         /**
148          * @brief Per-Note information
149          */
150         struct NoteInfo
151         {
152             //! Note number
153             uint8_t note;
154             //! Current pressure
155             uint8_t vol;
156             //! Note vibrato (a part of Note Aftertouch feature)
157             uint8_t vibrato;
158             //! Tone selected on noteon:
159             int16_t noteTone;
160             //! Current tone (!= noteTone if gliding note)
161             double currentTone;
162             //! Gliding rate
163             double glideRate;
164             //! Patch selected on noteon; index to bank.ins[]
165             size_t  midiins;
166             //! Is note the percussion instrument
167             bool    isPercussion;
168             //! Note that plays missing instrument. Doesn't using any chip channels
169             bool    isBlank;
170             //! Whether releasing and on extended life time defined by TTL
171             bool    isOnExtendedLifeTime;
172             //! Time-to-live until release (short percussion note fix)
173             double  ttl;
174             //! Patch selected
175             const OpnInstMeta *ains;
176             enum
177             {
178                 MaxNumPhysChans = 2,
179                 MaxNumPhysItemCount = MaxNumPhysChans
180             };
181 
182             struct FindPredicate
183             {
FindPredicateOPNMIDIplay::MIDIchannel::NoteInfo::FindPredicate184                 explicit FindPredicate(unsigned note)
185                     : note(note) {}
operator ()OPNMIDIplay::MIDIchannel::NoteInfo::FindPredicate186                 bool operator()(const NoteInfo &ni) const
187                     { return ni.note == note; }
188                 unsigned note;
189             };
190 
191             /**
192              * @brief Reference to currently using chip channel
193              */
194             struct Phys
195             {
196                 //! Destination chip channel
197                 uint16_t chip_chan;
198                 //! ins, inde to adl[]
199                 OpnTimbre ains;
200 
assignOPNMIDIplay::MIDIchannel::NoteInfo::Phys201                 void assign(const Phys &oth)
202                 {
203                     ains = oth.ains;
204                 }
operator ==OPNMIDIplay::MIDIchannel::NoteInfo::Phys205                 bool operator==(const Phys &oth) const
206                 {
207                     return (ains == oth.ains);
208                 }
operator !=OPNMIDIplay::MIDIchannel::NoteInfo::Phys209                 bool operator!=(const Phys &oth) const
210                 {
211                     return !operator==(oth);
212                 }
213             };
214 
215             //! List of OPN2 channels it is currently occupying.
216             Phys chip_channels[MaxNumPhysItemCount];
217             //! Count of used channels.
218             unsigned chip_channels_count;
219 
phys_findOPNMIDIplay::MIDIchannel::NoteInfo220             Phys *phys_find(unsigned chip_chan)
221             {
222                 Phys *ph = NULL;
223                 for(unsigned i = 0; i < chip_channels_count && !ph; ++i)
224                     if(chip_channels[i].chip_chan == chip_chan)
225                         ph = &chip_channels[i];
226                 return ph;
227             }
phys_find_or_createOPNMIDIplay::MIDIchannel::NoteInfo228             Phys *phys_find_or_create(uint16_t chip_chan)
229             {
230                 Phys *ph = phys_find(chip_chan);
231                 if(!ph) {
232                     if(chip_channels_count < MaxNumPhysItemCount) {
233                         ph = &chip_channels[chip_channels_count++];
234                         ph->chip_chan = chip_chan;
235                     }
236                 }
237                 return ph;
238             }
phys_ensure_find_or_createOPNMIDIplay::MIDIchannel::NoteInfo239             Phys *phys_ensure_find_or_create(uint16_t chip_chan)
240             {
241                 Phys *ph = phys_find_or_create(chip_chan);
242                 assert(ph);
243                 return ph;
244             }
phys_erase_atOPNMIDIplay::MIDIchannel::NoteInfo245             void phys_erase_at(const Phys *ph)
246             {
247                 intptr_t pos = ph - chip_channels;
248                 assert(pos < static_cast<intptr_t>(chip_channels_count));
249                 for(intptr_t i = pos + 1; i < static_cast<intptr_t>(chip_channels_count); ++i)
250                     chip_channels[i - 1] = chip_channels[i];
251                 --chip_channels_count;
252             }
phys_eraseOPNMIDIplay::MIDIchannel::NoteInfo253             void phys_erase(unsigned chip_chan)
254             {
255                 Phys *ph = phys_find(chip_chan);
256                 if(ph)
257                     phys_erase_at(ph);
258             }
259         };
260 
261         //! Reserved
262         char _padding2[5];
263         //! Count of gliding notes in this channel
264         unsigned gliding_note_count;
265         //! Count of notes having a TTL countdown in this channel
266         unsigned extended_note_count;
267 
268         //! Active notes in the channel
269         pl_list<NoteInfo> activenotes;
270         typedef pl_list<NoteInfo>::iterator notes_iterator;
271         typedef pl_list<NoteInfo>::const_iterator const_notes_iterator;
272 
find_activenoteOPNMIDIplay::MIDIchannel273         notes_iterator find_activenote(unsigned note)
274         {
275             return activenotes.find_if(NoteInfo::FindPredicate(note));
276         }
277 
ensure_find_activenoteOPNMIDIplay::MIDIchannel278         notes_iterator ensure_find_activenote(unsigned note)
279         {
280             notes_iterator it = find_activenote(note);
281             assert(!it.is_end());
282             return it;
283         }
284 
find_or_create_activenoteOPNMIDIplay::MIDIchannel285         notes_iterator find_or_create_activenote(unsigned note)
286         {
287             notes_iterator it = find_activenote(note);
288             if(!it.is_end())
289                 cleanupNote(it);
290             else
291             {
292                 NoteInfo ni;
293                 ni.note = note;
294                 it = activenotes.insert(activenotes.end(), ni);
295             }
296             return it;
297         }
298 
ensure_find_or_create_activenoteOPNMIDIplay::MIDIchannel299         notes_iterator ensure_find_or_create_activenote(unsigned note)
300         {
301             notes_iterator it = find_or_create_activenote(note);
302             assert(!it.is_end());
303             return it;
304         }
305 
306         /**
307          * @brief Reset channel into initial state
308          */
resetOPNMIDIplay::MIDIchannel309         void reset()
310         {
311             resetAllControllers();
312             patch = 0;
313             vibpos = 0;
314             bank_lsb = 0;
315             bank_msb = 0;
316             lastlrpn = 0;
317             lastmrpn = 0;
318             nrpn = false;
319             is_xg_percussion = false;
320         }
321 
322 
resetAllControllersOPNMIDIplay::MIDIchannel323         void resetAllControllers()
324         {
325             volume  = def_volume;
326             brightness = 127;
327             panning = 64;
328 
329             resetAllControllers121();
330         }
331 
332         /**
333          * @brief Reset all MIDI controllers into initial state
334          */
resetAllControllers121OPNMIDIplay::MIDIchannel335         void resetAllControllers121()
336         {
337             bend = 0;
338             bendsense_msb = def_bendsense_msb;
339             bendsense_lsb = def_bendsense_lsb;
340             updateBendSensitivity();
341             expression = 127;
342             sustain = false;
343             softPedal = false;
344             vibrato = 0;
345             aftertouch = 0;
346             std::memset(noteAftertouch, 0, 128);
347             noteAfterTouchInUse = false;
348             vibspeed = 2 * 3.141592653 * 5.0;
349             vibdepth = 0.5 / 127;
350             vibdelay_us = 0;
351             portamento = 0;
352             portamentoEnable = false;
353             portamentoSource = -1;
354             portamentoRate = HUGE_VAL;
355         }
356 
357         /**
358          * @brief Has channel vibrato to process
359          * @return
360          */
hasVibratoOPNMIDIplay::MIDIchannel361         bool hasVibrato()
362         {
363             return (vibrato > 0) || (aftertouch > 0) || noteAfterTouchInUse;
364         }
365 
366         /**
367          * @brief Commit pitch bend sensitivity value from MSB and LSB
368          */
updateBendSensitivityOPNMIDIplay::MIDIchannel369         void updateBendSensitivity()
370         {
371             int cent = bendsense_msb * 128 + bendsense_lsb;
372             bendsense = cent * (1.0 / (128 * 8192));
373         }
374 
375         /**
376          * @brief Clean up the state of the active note before removal
377          */
cleanupNoteOPNMIDIplay::MIDIchannel378         void cleanupNote(notes_iterator i)
379         {
380             NoteInfo &info = i->value;
381             if(info.glideRate != HUGE_VAL)
382                 --gliding_note_count;
383             if(info.ttl > 0)
384                 --extended_note_count;
385         }
386 
MIDIchannelOPNMIDIplay::MIDIchannel387         MIDIchannel() :
388             def_volume(100),
389             def_bendsense_lsb(0),
390             def_bendsense_msb(2),
391             activenotes(128)
392         {
393             gliding_note_count = 0;
394             extended_note_count = 0;
395             reset();
396         }
397     };
398 
399     /**
400      * @brief Additional information about OPN2 channels
401      */
402     struct OpnChannel
403     {
404         struct Location
405         {
406             uint16_t    MidCh;
407             uint8_t     note;
operator ==OPNMIDIplay::OpnChannel::Location408             bool operator==(const Location &l) const
409                 { return MidCh == l.MidCh && note == l.note; }
operator !=OPNMIDIplay::OpnChannel::Location410             bool operator!=(const Location &l) const
411                 { return !operator==(l); }
412             char _padding[1];
413         };
414         struct LocationData
415         {
416             Location loc;
417             enum {
418                 Sustain_None        = 0x00,
419                 Sustain_Pedal       = 0x01,
420                 Sustain_Sostenuto   = 0x02,
421                 Sustain_ANY         = Sustain_Pedal | Sustain_Sostenuto
422             };
423             uint32_t sustained;
424             char _padding[3];
425             MIDIchannel::NoteInfo::Phys ins;  // a copy of that in phys[]
426             //! Has fixed sustain, don't iterate "on" timeout
427             bool    fixed_sustain;
428             //! Timeout until note will be allowed to be killed by channel manager while it is on
429             int64_t kon_time_until_neglible_us;
430             int64_t vibdelay_us;
431 
432             struct FindPredicate
433             {
FindPredicateOPNMIDIplay::OpnChannel::LocationData::FindPredicate434                 explicit FindPredicate(Location loc)
435                     : loc(loc) {}
operator ()OPNMIDIplay::OpnChannel::LocationData::FindPredicate436                 bool operator()(const LocationData &ld) const
437                     { return ld.loc == loc; }
438                 Location loc;
439             };
440         };
441 
442         //! Time left until sounding will be muted after key off
443         int64_t koff_time_until_neglible_us;
444 
445         //! Recently passed instrument, improves a goodness of released but busy channel when matching
446         MIDIchannel::NoteInfo::Phys recent_ins;
447 
448         pl_list<LocationData> users;
449         typedef pl_list<LocationData>::iterator users_iterator;
450         typedef pl_list<LocationData>::const_iterator const_users_iterator;
451 
find_userOPNMIDIplay::OpnChannel452         users_iterator find_user(const Location &loc)
453         {
454             return users.find_if(LocationData::FindPredicate(loc));
455         }
456 
find_or_create_userOPNMIDIplay::OpnChannel457         users_iterator find_or_create_user(const Location &loc)
458         {
459             users_iterator it = find_user(loc);
460             if(it.is_end() && users.size() != users.capacity())
461             {
462                 LocationData ld;
463                 ld.loc = loc;
464                 it = users.insert(users.end(), ld);
465             }
466             return it;
467         }
468 
469         // For channel allocation:
OpnChannelOPNMIDIplay::OpnChannel470         OpnChannel(): koff_time_until_neglible_us(0), users(128)
471         {
472             std::memset(&recent_ins, 0, sizeof(MIDIchannel::NoteInfo::Phys));
473         }
474 
OpnChannelOPNMIDIplay::OpnChannel475         OpnChannel(const OpnChannel &oth): koff_time_until_neglible_us(oth.koff_time_until_neglible_us), users(oth.users)
476         {
477         }
478 
operator =OPNMIDIplay::OpnChannel479         OpnChannel &operator=(const OpnChannel &oth)
480         {
481             koff_time_until_neglible_us = oth.koff_time_until_neglible_us;
482             users = oth.users;
483             return *this;
484         }
485 
486         /**
487          * @brief Increases age of active note in microseconds time
488          * @param us Amount time in microseconds
489          */
490         void addAge(int64_t us);
491     };
492 
493 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
494     /**
495      * @brief MIDI files player sequencer
496      */
497     AdlMIDI_UPtr<MidiSequencer> m_sequencer;
498 
499     /**
500      * @brief Interface between MIDI sequencer and this library
501      */
502     AdlMIDI_UPtr<BW_MidiRtInterface> m_sequencerInterface;
503 
504     /**
505      * @brief Initialize MIDI sequencer interface
506      */
507     void initSequencerInterface();
508 #endif //OPNMIDI_DISABLE_MIDI_SEQUENCER
509 
510     struct Setup
511     {
512         int     emulator;
513         bool    runAtPcmRate;
514         unsigned int OpnBank;
515         unsigned int numChips;
516         unsigned int LogarithmicVolumes;
517         int     VolumeModel;
518         int     lfoEnable;
519         int     lfoFrequency;
520         int     chipType;
521         //unsigned int SkipForward;
522         int     ScaleModulators;
523         bool    fullRangeBrightnessCC74;
524 
525         double delay;
526         double carry;
527 
528         /* The lag between visual content and audio content equals */
529         /* the sum of these two buffers. */
530         double mindelay;
531         double maxdelay;
532 
533         /* For internal usage */
534         ssize_t tick_skip_samples_delay; /* Skip tick processing after samples count. */
535         /* For internal usage */
536 
537         unsigned long PCM_RATE;
538     };
539 
540     /**
541      * @brief MIDI Marker entry
542      */
543     struct MIDI_MarkerEntry
544     {
545         //! Label of marker
546         std::string     label;
547         //! Absolute position in seconds
548         double          pos_time;
549         //! Absolute position in ticks in the track
550         uint64_t        pos_ticks;
551     };
552 
553     //! Available MIDI Channels
554     std::vector<MIDIchannel> m_midiChannels;
555 
556     //! SysEx device ID
557     uint8_t m_sysExDeviceId;
558 
559     /**
560      * @brief MIDI Synthesizer mode
561      */
562     enum SynthMode
563     {
564         Mode_GM  = 0x00,
565         Mode_GS  = 0x01,
566         Mode_XG  = 0x02,
567         Mode_GM2 = 0x04
568     };
569     //! MIDI Synthesizer mode
570     uint32_t m_synthMode;
571 
572     //! Installed function hooks
573     MIDIEventHooks hooks;
574 
575 private:
576     //! Per-track MIDI devices map
577     std::map<std::string, size_t> m_midiDevices;
578     //! Current MIDI device per track
579     std::map<size_t /*track*/, size_t /*channel begin index*/> m_currentMidiDevice;
580 
581     //! Chip channels map
582     std::vector<OpnChannel> m_chipChannels;
583     //! Counter of arpeggio processing
584     size_t m_arpeggioCounter;
585 
586 #if defined(ADLMIDI_AUDIO_TICK_HANDLER)
587     //! Audio tick counter
588     uint32_t m_audioTickCounter;
589 #endif
590 
591     //! Local error string
592     std::string errorStringOut;
593 
594     //! Missing instruments catches
595     std::set<size_t> caugh_missing_instruments;
596     //! Missing melodic banks catches
597     std::set<size_t> caugh_missing_banks_melodic;
598     //! Missing percussion banks catches
599     std::set<size_t> caugh_missing_banks_percussion;
600 
601 public:
602 
603     const std::string &getErrorString();
604     void setErrorString(const std::string &err);
605 
606     //! OPN2 Chip manager
607     AdlMIDI_UPtr<Synth> m_synth;
608 
609     //! Generator output buffer
610     int32_t m_outBuf[1024];
611 
612     //! Synthesizer setup
613     Setup m_setup;
614 
615     /**
616      * @brief Load bank from file
617      * @param filename Path to bank file
618      * @return true on succes
619      */
620     bool LoadBank(const std::string &filename);
621 
622     /**
623      * @brief Load bank from memory block
624      * @param data Pointer to memory block where raw bank file is stored
625      * @param size Size of given memory block
626      * @return true on succes
627      */
628     bool LoadBank(const void *data, size_t size);
629 
630     /**
631      * @brief Load bank from opened FileAndMemReader class
632      * @param fr Instance with opened file
633      * @return true on succes
634      */
635     bool LoadBank(FileAndMemReader &fr);
636 
637 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
638     /**
639      * @brief MIDI file loading pre-process
640      * @return true on success, false on failure
641      */
642     bool LoadMIDI_pre();
643 
644     /**
645      * @brief MIDI file loading post-process
646      * @return true on success, false on failure
647      */
648     bool LoadMIDI_post();
649 
650     /**
651      * @brief Load music file from a file
652      * @param filename Path to music file
653      * @return true on success, false on failure
654      */
655 
656     bool LoadMIDI(const std::string &filename);
657 
658     /**
659      * @brief Load music file from the memory block
660      * @param data pointer to the memory block
661      * @param size size of memory block
662      * @return true on success, false on failure
663      */
664     bool LoadMIDI(const void *data, size_t size);
665 
666     /**
667      * @brief Periodic tick handler.
668      * @param s seconds since last call
669      * @param granularity don't expect intervals smaller than this, in seconds
670      * @return desired number of seconds until next call
671      */
672     double Tick(double s, double granularity);
673 #endif //OPNMIDI_DISABLE_MIDI_SEQUENCER
674 
675     /**
676      * @brief Process extra iterators like vibrato or arpeggio
677      * @param s seconds since last call
678      */
679     void   TickIterators(double s);
680 
681 
682     /* RealTime event triggers */
683     /**
684      * @brief Reset state of all channels
685      */
686     void realTime_ResetState();
687 
688     /**
689      * @brief Note On event
690      * @param channel MIDI channel
691      * @param note Note key (from 0 to 127)
692      * @param velocity Velocity level (from 0 to 127)
693      * @return true if Note On event was accepted
694      */
695     bool realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity);
696 
697     /**
698      * @brief Note Off event
699      * @param channel MIDI channel
700      * @param note Note key (from 0 to 127)
701      */
702     void realTime_NoteOff(uint8_t channel, uint8_t note);
703 
704     /**
705      * @brief Note aftertouch event
706      * @param channel MIDI channel
707      * @param note Note key (from 0 to 127)
708      * @param atVal After-Touch level (from 0 to 127)
709      */
710     void realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal);
711 
712     /**
713      * @brief Channel aftertouch event
714      * @param channel MIDI channel
715      * @param atVal After-Touch level (from 0 to 127)
716      */
717     void realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal);
718 
719     /**
720      * @brief Controller Change event
721      * @param channel MIDI channel
722      * @param type Type of controller
723      * @param value Value of the controller (from 0 to 127)
724      */
725     void realTime_Controller(uint8_t channel, uint8_t type, uint8_t value);
726 
727     /**
728      * @brief Patch change
729      * @param channel MIDI channel
730      * @param patch Patch Number (from 0 to 127)
731      */
732     void realTime_PatchChange(uint8_t channel, uint8_t patch);
733 
734     /**
735      * @brief Pitch bend change
736      * @param channel MIDI channel
737      * @param pitch Concoctated raw pitch value
738      */
739     void realTime_PitchBend(uint8_t channel, uint16_t pitch);
740 
741     /**
742      * @brief Pitch bend change
743      * @param channel MIDI channel
744      * @param msb MSB of pitch value
745      * @param lsb LSB of pitch value
746      */
747     void realTime_PitchBend(uint8_t channel, uint8_t msb, uint8_t lsb);
748 
749     /**
750      * @brief LSB Bank Change CC
751      * @param channel MIDI channel
752      * @param lsb LSB value of bank number
753      */
754     void realTime_BankChangeLSB(uint8_t channel, uint8_t lsb);
755 
756     /**
757      * @brief MSB Bank Change CC
758      * @param channel MIDI channel
759      * @param lsb MSB value of bank number
760      */
761     void realTime_BankChangeMSB(uint8_t channel, uint8_t msb);
762 
763     /**
764      * @brief Bank Change (united value)
765      * @param channel MIDI channel
766      * @param bank Bank number value
767      */
768     void realTime_BankChange(uint8_t channel, uint16_t bank);
769 
770     /**
771      * @brief Sets the Device identifier
772      * @param id 7-bit Device identifier
773      */
774     void setDeviceId(uint8_t id);
775 
776     /**
777      * @brief System Exclusive message
778      * @param msg Raw SysEx Message
779      * @param size Length of SysEx message
780      * @return true if message was passed successfully. False on any errors
781      */
782     bool realTime_SysEx(const uint8_t *msg, size_t size);
783 
784     /**
785      * @brief Turn off all notes and mute the sound of releasing notes
786      */
787     void realTime_panic();
788 
789     /**
790      * @brief Device switch (to extend 16-channels limit of MIDI standard)
791      * @param track MIDI track index
792      * @param data Device name
793      * @param length Length of device name string
794      */
795     void realTime_deviceSwitch(size_t track, const char *data, size_t length);
796 
797     /**
798      * @brief Currently selected device index
799      * @param track MIDI track index
800      * @return Multiple 16 value
801      */
802     size_t realTime_currentDevice(size_t track);
803 
804 #if defined(ADLMIDI_AUDIO_TICK_HANDLER)
805     // Audio rate tick handler
806     void AudioTick(uint32_t chipId, uint32_t rate);
807 #endif
808 
809 private:
810     /**
811      * @brief Hardware manufacturer (Used for SysEx)
812      */
813     enum
814     {
815         Manufacturer_Roland               = 0x41,
816         Manufacturer_Yamaha               = 0x43,
817         Manufacturer_UniversalNonRealtime = 0x7E,
818         Manufacturer_UniversalRealtime    = 0x7F
819     };
820 
821     /**
822      * @brief Roland Mode (Used for SysEx)
823      */
824     enum
825     {
826         RolandMode_Request = 0x11,
827         RolandMode_Send    = 0x12
828     };
829 
830     /**
831      * @brief Device model (Used for SysEx)
832      */
833     enum
834     {
835         RolandModel_GS   = 0x42,
836         RolandModel_SC55 = 0x45,
837         YamahaModel_XG   = 0x4C
838     };
839 
840     /**
841      * @brief Process generic SysEx events
842      * @param dev Device ID
843      * @param realtime Is real-time event
844      * @param data Raw SysEx data
845      * @param size Size of given SysEx data
846      * @return true when event was successfully handled
847      */
848     bool doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size);
849 
850     /**
851      * @brief Process events specific to Roland devices
852      * @param dev Device ID
853      * @param data Raw SysEx data
854      * @param size Size of given SysEx data
855      * @return true when event was successfully handled
856      */
857     bool doRolandSysEx(unsigned dev, const uint8_t *data, size_t size);
858 
859     /**
860      * @brief Process events specific to Yamaha devices
861      * @param dev Device ID
862      * @param data Raw SysEx data
863      * @param size Size of given SysEx data
864      * @return true when event was successfully handled
865      */
866     bool doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size);
867 
868 private:
869     /**
870      * @brief Note Update properties
871      */
872     enum
873     {
874         Upd_Patch  = 0x1,
875         Upd_Pan    = 0x2,
876         Upd_Volume = 0x4,
877         Upd_Pitch  = 0x8,
878         Upd_All    = Upd_Pan + Upd_Volume + Upd_Pitch,
879         Upd_Off    = 0x20,
880         Upd_Mute   = 0x40,
881         Upd_OffMute = Upd_Off + Upd_Mute
882     };
883 
884     /**
885      * @brief Update active note
886      * @param MidCh MIDI Channel where note is processing
887      * @param i Iterator that points to active note in the MIDI channel
888      * @param props_mask Properties to update
889      * @param select_adlchn Specify chip channel, or -1 - all chip channels used by the note
890      */
891     void noteUpdate(size_t midCh,
892                     MIDIchannel::notes_iterator i,
893                     unsigned props_mask,
894                     int32_t select_adlchn = -1);
895 
896     void noteUpdateAll(size_t midCh, unsigned props_mask);
897 
898     /**
899      * @brief Determine how good a candidate this adlchannel would be for playing a note from this instrument.
900      * @param c Wanted chip channel
901      * @param ins Instrument wanted to be used in this channel
902      * @return Calculated coodness points
903      */
904     int64_t calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const;
905 
906     /**
907      * @brief A new note will be played on this channel using this instrument.
908      * @param c Wanted chip channel
909      * @param ins Instrument wanted to be used in this channel
910      * Kill existing notes on this channel (or don't, if we do arpeggio)
911      */
912     void prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins);
913 
914     /**
915      * @brief Kills note that uses wanted channel. When arpeggio is possible, note is evaluating to another channel
916      * @param from_channel Wanted chip channel
917      * @param j Chip channel instance
918      * @param i MIDI Channel active note instance
919      */
920     void killOrEvacuate(
921         size_t  from_channel,
922         OpnChannel::users_iterator j,
923         MIDIchannel::notes_iterator i);
924 
925     /**
926      * @brief Off all notes and silence sound
927      */
928     void panic();
929 
930     /**
931      * @brief Kill note, sustaining by pedal or sostenuto
932      * @param MidCh MIDI channel, -1 - all MIDI channels
933      * @param this_adlchn Chip channel, -1 - all chip channels
934      * @param sustain_type Type of systain to process
935      */
936     void killSustainingNotes(int32_t midCh = -1,
937                              int32_t this_adlchn = -1,
938                              uint32_t sustain_type = OpnChannel::LocationData::Sustain_ANY);
939     /**
940      * @brief Find active notes and mark them as sostenuto-sustained
941      * @param MidCh MIDI channel, -1 - all MIDI channels
942      */
943     void markSostenutoNotes(int32_t midCh = -1);
944 
945     /**
946      * @brief Set RPN event value
947      * @param MidCh MIDI channel
948      * @param value 1 byte part of RPN value
949      * @param MSB is MSB or LSB part of value
950      */
951     void setRPN(size_t midCh, unsigned value, bool MSB);
952 
953     /**
954      * @brief Update portamento setup in MIDI channel
955      * @param midCh MIDI channel where portamento needed to be updated
956      */
957     void updatePortamento(size_t midCh);
958 
959     /**
960      * @brief Off the note
961      * @param midCh MIDI channel
962      * @param note Note to off
963      * @param forceNow Do not delay the key-off to a later time
964      */
965     void noteOff(size_t midCh, uint8_t note, bool forceNow = false);
966 
967     /**
968      * @brief Update processing of vibrato to amount of seconds
969      * @param amount Amount value in seconds
970      */
971     void updateVibrato(double amount);
972 
973     /**
974      * @brief Update auto-arpeggio
975      * @param amount Amount value in seconds [UNUSED]
976      */
977     void updateArpeggio(double /*amount*/);
978 
979     /**
980      * @brief Update Portamento gliding to amount of seconds
981      * @param amount Amount value in seconds
982      */
983     void updateGlide(double amount);
984 
985 public:
986     /**
987      * @brief Checks was device name used or not
988      * @param name Name of MIDI device
989      * @return Offset of the MIDI Channels, multiple to 16
990      */
991     size_t chooseDevice(const std::string &name);
992 
993     /**
994      * @brief Gets a textual description of the state of chip channels
995      * @param text character pointer for text
996      * @param attr character pointer for text attributes
997      * @param size number of characters available to write
998      */
999     void describeChannels(char *text, char *attr, size_t size);
1000 };
1001 
1002 #endif // OPNMIDI_MIDIPLAY_HPP
1003