1 //-----------------------------------------------------------------------------
2 // Project : VST SDK
3 //
4 // Category : Examples
5 // Filename : public.sdk/samples/vst/hostchecker/source/eventlistcheck.cpp
6 // Created by : Steinberg, 12/2012
7 // Description : Event List check
8 //
9 //-----------------------------------------------------------------------------
10 // LICENSE
11 // (c) 2018, Steinberg Media Technologies GmbH, All Rights Reserved
12 //-----------------------------------------------------------------------------
13 // Redistribution and use in source and binary forms, with or without modification,
14 // are permitted provided that the following conditions are met:
15 //
16 // * Redistributions of source code must retain the above copyright notice,
17 // this list of conditions and the following disclaimer.
18 // * Redistributions in binary form must reproduce the above copyright notice,
19 // this list of conditions and the following disclaimer in the documentation
20 // and/or other materials provided with the distribution.
21 // * Neither the name of the Steinberg Media Technologies nor the names of its
22 // contributors may be used to endorse or promote products derived from this
23 // software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34 // OF THE POSSIBILITY OF SUCH DAMAGE.
35 //-----------------------------------------------------------------------------
36
37 #include "eventlistcheck.h"
38 #include "eventlogger.h"
39 #include "logevents.h"
40 #include "pluginterfaces/vst/ivstcomponent.h"
41 #include "pluginterfaces/vst/ivstevents.h"
42
43 //------------------------------------------------------------------------
44 // EventListCheck
45 //------------------------------------------------------------------------
EventListCheck()46 EventListCheck::EventListCheck () : mEventLogger (nullptr), mComponent (nullptr)
47 {
48 }
49
50 //------------------------------------------------------------------------
check(Steinberg::Vst::IEventList * events)51 void EventListCheck::check (Steinberg::Vst::IEventList* events)
52 {
53 if (events)
54 {
55 if (!checkEventCount (events))
56 mEventLogger->addLogEvent (kLogIdNumInputEventExceedsLimit);
57
58 Steinberg::int32 lastSampleOffset = 0;
59 Steinberg::Vst::TQuarterNotes lastPpqPosition = 0;
60 Steinberg::int32 eventCount = events->getEventCount ();
61 for (Steinberg::int32 eventIdx = 0; eventIdx < eventCount; ++eventIdx)
62 {
63 Steinberg::Vst::Event event = {};
64 Steinberg::tresult tResult = events->getEvent (eventIdx, event);
65 if (tResult != Steinberg::kResultOk)
66 {
67 mEventLogger->addLogEvent (kLogIdCouldNotGetAnInputEvent);
68 continue;
69 }
70
71 if (event.sampleOffset < lastSampleOffset)
72 {
73 mEventLogger->addLogEvent (kLogIdEventsAreNotSortedBySampleOffset);
74 lastSampleOffset = event.sampleOffset;
75 }
76
77 if (event.ppqPosition < lastPpqPosition)
78 {
79 mEventLogger->addLogEvent (kLogIdEventsAreNotSortedByPpqPosition);
80 event.ppqPosition = lastPpqPosition;
81 }
82
83 checkEventProperties (event);
84 }
85 }
86 }
87
88 //------------------------------------------------------------------------
checkEventCount(Steinberg::Vst::IEventList * events)89 bool EventListCheck::checkEventCount (Steinberg::Vst::IEventList* events)
90 {
91 if (events)
92 {
93 return events->getEventCount () >= 0 || events->getEventCount () < kMaxEvents;
94 }
95
96 return true;
97 }
98
99 //------------------------------------------------------------------------
checkEventProperties(const Steinberg::Vst::Event & event)100 void EventListCheck::checkEventProperties (const Steinberg::Vst::Event& event)
101 {
102 //! TODO: Make this method smaller
103 if (!checkEventBusIndex (event.busIndex))
104 {
105 mEventLogger->addLogEvent (kLogIdInvalidEventBusIndex);
106 return;
107 }
108
109 if (!checkEventSampleOffset (event.sampleOffset))
110 {
111 mEventLogger->addLogEvent (kLogIdInvalidEventSampleOffset);
112 }
113
114 switch (event.type)
115 {
116 case Steinberg::Vst::Event::kNoteOnEvent:
117 {
118 if (!checkEventChannelIndex (event.busIndex, event.noteOn.channel))
119 mEventLogger->addLogEvent (kLogIdInvalidNoteOnChannelIndex);
120
121 if (!isNormalized (event.noteOn.velocity))
122 mEventLogger->addLogEvent (kLogIdInvalidEventVelocityValue);
123
124 if (!checkValidPitch (event.noteOn.pitch))
125 mEventLogger->addLogEvent (kLogIdInvalidEventPitchValue);
126
127 if (mNotePitches.find (event.noteOn.pitch) != mNotePitches.end ())
128 {
129 mEventLogger->addLogEvent (kLogIdNoteOnWithPitchAlreadyTriggered);
130 }
131
132 mNotePitches.insert (event.noteOn.pitch);
133
134 if (event.noteOn.noteId >= 0)
135 {
136 if (mNoteIDs.find (event.noteOn.noteId) != mNoteIDs.end ())
137 mEventLogger->addLogEvent (kLogIdNoteOnWithIdAlreadyTriggered);
138 }
139
140 mNoteIDs.insert (event.noteOn.noteId);
141
142 break;
143 }
144
145 case Steinberg::Vst::Event::kNoteOffEvent: ///< is \ref NoteOffEvent
146 {
147 if (!checkEventChannelIndex (event.busIndex, event.noteOff.channel))
148 mEventLogger->addLogEvent (kLogIdInvalidNoteOffChannelIndex);
149
150 if (!isNormalized (event.noteOff.velocity))
151 mEventLogger->addLogEvent (kLogIdInvalidEventVelocityValue);
152
153 if (!checkValidPitch (event.noteOff.pitch))
154 mEventLogger->addLogEvent (kLogIdInvalidEventPitchValue);
155
156 if (mNotePitches.find (event.noteOff.pitch) == mNotePitches.end ())
157 {
158 mEventLogger->addLogEvent (kLogIdNoteOffWithPitchNeverTriggered);
159 }
160
161 mNotePitches.erase (event.noteOff.pitch);
162
163 if (event.noteOff.noteId >= 0)
164 {
165 if (mNoteIDs.find (event.noteOff.noteId) == mNoteIDs.end ())
166 {
167 mEventLogger->addLogEvent (kLogIdNoteOffWithIdNeverTriggered);
168 }
169 }
170
171 mNoteIDs.erase (event.noteOff.noteId);
172
173 break;
174 }
175
176 case Steinberg::Vst::Event::kDataEvent: ///< is \ref DataEvent
177 {
178 break;
179 }
180
181 case Steinberg::Vst::Event::kPolyPressureEvent: ///< is \ref PolyPressureEvent
182 {
183 if (!checkEventChannelIndex (event.busIndex, event.polyPressure.channel))
184 mEventLogger->addLogEvent (kLogIdInvalidPolyPressChannelIndex);
185
186 break;
187 }
188
189 case Steinberg::Vst::Event::kNoteExpressionValueEvent: ///< is \ref NoteExpressionValueEvent
190 {
191 if (!isNormalized (event.noteExpressionValue.value))
192 mEventLogger->addLogEvent (kLogIdNoteExpressValNotNormalized);
193
194 checkNoteExpressionValueEvent (event.noteExpressionValue.typeId,
195 event.noteExpressionValue.noteId,
196 event.noteExpressionValue.value);
197 break;
198 }
199
200 default:
201 {
202 mEventLogger->addLogEvent (kLogIdUnknownEventType);
203 break;
204 }
205 }
206 }
207
208 //------------------------------------------------------------------------
checkEventBusIndex(Steinberg::int32 busIndex)209 bool EventListCheck::checkEventBusIndex (Steinberg::int32 busIndex)
210 {
211 if (mComponent)
212 {
213 Steinberg::int32 busCount =
214 mComponent->getBusCount (Steinberg::Vst::kEvent, Steinberg::Vst::kInput);
215 return busCount >= 0 && busIndex < busCount;
216 }
217
218 return false;
219 }
220
221 //------------------------------------------------------------------------
checkEventSampleOffset(Steinberg::int32 sampleOffset)222 bool EventListCheck::checkEventSampleOffset (Steinberg::int32 sampleOffset)
223 {
224 return sampleOffset >= 0 && sampleOffset < mSetup.maxSamplesPerBlock;
225 }
226
227 //------------------------------------------------------------------------
checkEventChannelIndex(Steinberg::int32 busIndex,Steinberg::int32 channelIndex)228 bool EventListCheck::checkEventChannelIndex (Steinberg::int32 busIndex,
229 Steinberg::int32 channelIndex)
230 {
231 if (mComponent)
232 {
233 Steinberg::int32 busCount =
234 mComponent->getBusCount (Steinberg::Vst::kEvent, Steinberg::Vst::kInput);
235 if (busCount >= 0 && busIndex < busCount)
236 {
237 Steinberg::Vst::BusInfo busInfo = {0};
238 Steinberg::tresult tResult = mComponent->getBusInfo (
239 Steinberg::Vst::kEvent, Steinberg::Vst::kInput, busIndex, busInfo);
240 if (tResult == Steinberg::kResultOk)
241 {
242 return channelIndex >= 0 && channelIndex < busInfo.channelCount;
243 }
244 }
245 }
246
247 return false;
248 }
249
250 //------------------------------------------------------------------------
checkValidPitch(Steinberg::int16 pitch)251 bool EventListCheck::checkValidPitch (Steinberg::int16 pitch)
252 {
253 return pitch >= 0 && pitch <= 127;
254 }
255
256 //------------------------------------------------------------------------
isNormalized(float normVal) const257 bool EventListCheck::isNormalized (float normVal) const
258 {
259 return normVal >= 0. && normVal <= 1.;
260 }
261
262 //------------------------------------------------------------------------
checkNoteExpressionValueEvent(Steinberg::Vst::NoteExpressionTypeID,Steinberg::int32,Steinberg::Vst::NoteExpressionValue exprVal) const263 void EventListCheck::checkNoteExpressionValueEvent (
264 Steinberg::Vst::NoteExpressionTypeID /*type*/, Steinberg::int32 /*id*/,
265 Steinberg::Vst::NoteExpressionValue exprVal) const
266 {
267 if (!isNormalized (exprVal))
268 {
269 //! Todo
270 }
271 }
272
273 //------------------------------------------------------------------------
setProcessSetup(Steinberg::Vst::ProcessSetup setup)274 void EventListCheck::setProcessSetup (Steinberg::Vst::ProcessSetup setup)
275 {
276 mSetup = setup;
277 }
278
279 //------------------------------------------------------------------------
setEventLogger(EventLogger * eventLogger)280 void EventListCheck::setEventLogger (EventLogger* eventLogger)
281 {
282 mEventLogger = eventLogger;
283 }
284