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