1 /*
2  * libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
3  *
4  * Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
5  * ADLMIDI Library API:   Copyright (c) 2015-2018 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 ADLMIDI_DISABLE_MIDI_SEQUENCER
25 
26 // Rename class to avoid ABI collisions
27 #define BW_MidiSequencer AdlMidiSequencer
28 // Inlucde MIDI sequencer class implementation
29 #include "midi_sequencer_impl.hpp"
30 
31 #include "adlmidi_private.hpp"
32 
33 /****************************************************
34  *           Real-Time MIDI calls proxies           *
35  ****************************************************/
36 
rtNoteOn(void * userdata,uint8_t channel,uint8_t note,uint8_t velocity)37 static void rtNoteOn(void *userdata, uint8_t channel, uint8_t note, uint8_t velocity)
38 {
39     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
40     context->realTime_NoteOn(channel, note, velocity);
41 }
42 
rtNoteOff(void * userdata,uint8_t channel,uint8_t note)43 static void rtNoteOff(void *userdata, uint8_t channel, uint8_t note)
44 {
45     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
46     context->realTime_NoteOff(channel, note);
47 }
48 
rtNoteAfterTouch(void * userdata,uint8_t channel,uint8_t note,uint8_t atVal)49 static void rtNoteAfterTouch(void *userdata, uint8_t channel, uint8_t note, uint8_t atVal)
50 {
51     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
52     context->realTime_NoteAfterTouch(channel, note, atVal);
53 }
54 
rtChannelAfterTouch(void * userdata,uint8_t channel,uint8_t atVal)55 static void rtChannelAfterTouch(void *userdata, uint8_t channel, uint8_t atVal)
56 {
57     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
58     context->realTime_ChannelAfterTouch(channel, atVal);
59 }
60 
rtControllerChange(void * userdata,uint8_t channel,uint8_t type,uint8_t value)61 static void rtControllerChange(void *userdata, uint8_t channel, uint8_t type, uint8_t value)
62 {
63     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
64     context->realTime_Controller(channel, type, value);
65 }
66 
rtPatchChange(void * userdata,uint8_t channel,uint8_t patch)67 static void rtPatchChange(void *userdata, uint8_t channel, uint8_t patch)
68 {
69     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
70     context->realTime_PatchChange(channel, patch);
71 }
72 
rtPitchBend(void * userdata,uint8_t channel,uint8_t msb,uint8_t lsb)73 static void rtPitchBend(void *userdata, uint8_t channel, uint8_t msb, uint8_t lsb)
74 {
75     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
76     context->realTime_PitchBend(channel, msb, lsb);
77 }
78 
rtSysEx(void * userdata,const uint8_t * msg,size_t size)79 static void rtSysEx(void *userdata, const uint8_t *msg, size_t size)
80 {
81     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
82     context->realTime_SysEx(msg, size);
83 }
84 
85 
86 /* NonStandard calls */
rtRawOPL(void * userdata,uint8_t reg,uint8_t value)87 static void rtRawOPL(void *userdata, uint8_t reg, uint8_t value)
88 {
89     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
90     return context->realTime_rawOPL(reg, value);
91 }
92 
rtDeviceSwitch(void * userdata,size_t track,const char * data,size_t length)93 static void rtDeviceSwitch(void *userdata, size_t track, const char *data, size_t length)
94 {
95     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
96     context->realTime_deviceSwitch(track, data, length);
97 }
98 
rtCurrentDevice(void * userdata,size_t track)99 static size_t rtCurrentDevice(void *userdata, size_t track)
100 {
101     MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata);
102     return context->realTime_currentDevice(track);
103 }
104 /* NonStandard calls End */
105 
106 
initSequencerInterface()107 void MIDIplay::initSequencerInterface()
108 {
109     std::memset(&m_sequencerInterface, 0, sizeof(BW_MidiRtInterface));
110 
111     m_sequencerInterface.onDebugMessage             = hooks.onDebugMessage;
112     m_sequencerInterface.onDebugMessage_userData    = hooks.onDebugMessage_userData;
113 
114     /* MIDI Real-Time calls */
115     m_sequencerInterface.rtUserData = this;
116     m_sequencerInterface.rt_noteOn  = rtNoteOn;
117     m_sequencerInterface.rt_noteOff = rtNoteOff;
118     m_sequencerInterface.rt_noteAfterTouch = rtNoteAfterTouch;
119     m_sequencerInterface.rt_channelAfterTouch = rtChannelAfterTouch;
120     m_sequencerInterface.rt_controllerChange = rtControllerChange;
121     m_sequencerInterface.rt_patchChange = rtPatchChange;
122     m_sequencerInterface.rt_pitchBend = rtPitchBend;
123     m_sequencerInterface.rt_systemExclusive = rtSysEx;
124 
125     /* NonStandard calls */
126     m_sequencerInterface.rt_rawOPL = rtRawOPL;
127     m_sequencerInterface.rt_deviceSwitch = rtDeviceSwitch;
128     m_sequencerInterface.rt_currentDevice = rtCurrentDevice;
129     /* NonStandard calls End */
130 
131     m_sequencer.setInterface(&m_sequencerInterface);
132 }
133 
Tick(double s,double granularity)134 double MIDIplay::Tick(double s, double granularity)
135 {
136     double ret = m_sequencer.Tick(s, granularity);
137 
138     s *= m_sequencer.getTempoMultiplier();
139     for(uint16_t c = 0; c < m_synth.m_numChannels; ++c)
140         m_chipChannels[c].addAge(static_cast<int64_t>(s * 1000.0));
141 
142     updateVibrato(s);
143     updateArpeggio(s);
144 #if !defined(ADLMIDI_AUDIO_TICK_HANDLER)
145     updateGlide(s);
146 #endif
147 
148     return ret;
149 }
150 
151 #endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */
152