/[svn]/linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2871 - (show annotations) (download)
Sun Apr 10 18:22:23 2016 UTC (7 years, 11 months ago) by schoenebeck
File size: 11189 byte(s)
* All engines: Implemented scheduler for delayed MIDI events and for
  suspended real-time instrument scripts.
* Real-Time instrument scripts: Implemented support for built-in "wait()"
  function's "duration-us" argument, thus scripts using this function are
  now correctly resumed after the requested amount of microseconds.
* Real-Time instrument scripts: Implemented support for built-in
  "play_note()" function's "duration-us" argument, thus notes triggered
  with this argument are now correctly released after the requested amount
  of microseconds.
* Real-Time instrument scripts: Fixed crash which happened when trying to
  reference an undeclared script variable.
* Real-Time instrument scripts: Script events were not cleared when
  engine channel was reset, potentially causing undefined behavior.
* All engines: Attempt to partly fix resetting engine channels vs.
  resetting engine, an overall cleanup of the Reset*(),
  ConnectAudioDevice(), DisconnectAudioDevice() API methods would still be
  desirable though, because the current situation is still inconsistent
  and error prone.
* Bumped version (2.0.0.svn2).

1 /*
2 * Copyright (c) 2014-2016 Christian Schoenebeck
3 *
4 * http://www.linuxsampler.org
5 *
6 * This file is part of LinuxSampler and released under the same terms.
7 * See README file for details.
8 */
9
10 #include "InstrumentScriptVMFunctions.h"
11 #include "InstrumentScriptVM.h"
12 #include "../AbstractEngineChannel.h"
13
14 namespace LinuxSampler {
15
16 InstrumentScriptVMFunction_play_note::InstrumentScriptVMFunction_play_note(InstrumentScriptVM* parent)
17 : m_vm(parent)
18 {
19 }
20
21 VMFnResult* InstrumentScriptVMFunction_play_note::exec(VMFnArgs* args) {
22 int note = args->arg(0)->asInt()->evalInt();
23 int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
24 int sampleoffset = (args->argsCount() >= 3) ? args->arg(2)->asInt()->evalInt() : 0;
25 int duration = (args->argsCount() >= 4) ? args->arg(3)->asInt()->evalInt() : 0; //TODO: once -1 is implemented, it might be a better default value instead of 0
26
27 if (note < 0 || note > 127) {
28 errMsg("play_note(): argument 1 is an invalid note number");
29 return errorResult(-1);
30 }
31
32 if (velocity < 0 || velocity > 127) {
33 errMsg("play_note(): argument 2 is an invalid velocity value");
34 return errorResult(-1);
35 }
36
37 if (sampleoffset < 0) {
38 errMsg("play_note(): argument 3 may not be a negative sample offset");
39 return errorResult(-1);
40 } else if (sampleoffset != 0) {
41 wrnMsg("play_note(): argument 3 does not support a sample offset other than 0 yet");
42 }
43
44 if (duration < -1) {
45 errMsg("play_note(): argument 4 must be a duration value of at least -1 or higher");
46 return errorResult(-1);
47 } else if (duration == -1) {
48 wrnMsg("play_note(): argument 4 does not support special value -1 as duration yet");
49 }
50
51 AbstractEngineChannel* pEngineChannel =
52 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
53
54 Event e = m_vm->m_event->cause;
55 e.Type = Event::type_note_on;
56 e.Param.Note.Key = note;
57 e.Param.Note.Velocity = velocity;
58 memset(&e.Format, 0, sizeof(e.Format)); // init format specific stuff with zero
59
60 int id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
61
62 // if a duration is supplied, then schedule a subsequent note-ff event
63 if (duration > 0) {
64 e.Type = Event::type_note_off;
65 e.Param.Note.Velocity = 127;
66 pEngineChannel->ScheduleEventMicroSec(&e, duration);
67 }
68
69 return successResult(id);
70 }
71
72 InstrumentScriptVMFunction_set_controller::InstrumentScriptVMFunction_set_controller(InstrumentScriptVM* parent)
73 : m_vm(parent)
74 {
75 }
76
77 VMFnResult* InstrumentScriptVMFunction_set_controller::exec(VMFnArgs* args) {
78 int controller = args->arg(0)->asInt()->evalInt();
79 int value = args->arg(1)->asInt()->evalInt();
80
81 AbstractEngineChannel* pEngineChannel =
82 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
83
84 Event e = m_vm->m_event->cause;
85 memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero
86 if (controller == CTRL_TABLE_IDX_AFTERTOUCH) {
87 e.Type = Event::type_channel_pressure;
88 e.Param.ChannelPressure.Value = value & 127;
89 } else if (controller == CTRL_TABLE_IDX_PITCHBEND) {
90 e.Type = Event::type_pitchbend;
91 e.Param.Pitch.Pitch = value;
92 } else if (controller >= 0 && controller <= 127) {
93 e.Type = Event::type_control_change;
94 e.Param.CC.Controller = controller;
95 e.Param.CC.Value = value;
96 } else {
97 errMsg("set_controller(): argument 1 is an invalid controller");
98 return errorResult();
99 }
100
101 int id = pEngineChannel->ScheduleEventMicroSec(&e, 0);
102
103 return successResult(id);
104 }
105
106 InstrumentScriptVMFunction_ignore_event::InstrumentScriptVMFunction_ignore_event(InstrumentScriptVM* parent)
107 : m_vm(parent)
108 {
109 }
110
111 bool InstrumentScriptVMFunction_ignore_event::acceptsArgType(int iArg, ExprType_t type) const {
112 return type == INT_EXPR || type == INT_ARR_EXPR;
113 }
114
115 VMFnResult* InstrumentScriptVMFunction_ignore_event::exec(VMFnArgs* args) {
116 AbstractEngineChannel* pEngineChannel =
117 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
118
119 if (args->arg(0)->exprType() == INT_EXPR) {
120 int id = args->arg(0)->asInt()->evalInt();
121 if (id < 0) {
122 wrnMsg("ignore_event(): argument may not be a negative event ID");
123 return successResult();
124 }
125 pEngineChannel->IgnoreEvent(id);
126 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
127 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
128 for (int i = 0; i < ids->arraySize(); ++i) {
129 int id = ids->evalIntElement(i);
130 pEngineChannel->IgnoreEvent(id);
131 }
132 }
133
134 return successResult();
135 }
136
137 InstrumentScriptVMFunction_ignore_controller::InstrumentScriptVMFunction_ignore_controller(InstrumentScriptVM* parent)
138 : m_vm(parent)
139 {
140 }
141
142 VMFnResult* InstrumentScriptVMFunction_ignore_controller::exec(VMFnArgs* args) {
143 int id = (args->argsCount() >= 1) ? args->arg(0)->asInt()->evalInt() : m_vm->m_event->id;
144 if (id < 0) {
145 wrnMsg("ignore_controller(): argument may not be a negative event ID");
146 return successResult();
147 }
148
149 AbstractEngineChannel* pEngineChannel =
150 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
151
152 pEngineChannel->IgnoreEvent(id);
153
154 return successResult();
155 }
156
157 InstrumentScriptVMFunction_note_off::InstrumentScriptVMFunction_note_off(InstrumentScriptVM* parent)
158 : m_vm(parent)
159 {
160 }
161
162 bool InstrumentScriptVMFunction_note_off::acceptsArgType(int iArg, ExprType_t type) const {
163 return type == INT_EXPR || type == INT_ARR_EXPR;
164 }
165
166 VMFnResult* InstrumentScriptVMFunction_note_off::exec(VMFnArgs* args) {
167 AbstractEngineChannel* pEngineChannel =
168 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
169
170 int velocity = (args->argsCount() >= 2) ? args->arg(1)->asInt()->evalInt() : 127;
171 if (velocity < 0 || velocity > 127) {
172 errMsg("note_off(): argument 2 is an invalid velocity value");
173 return errorResult();
174 }
175
176 if (args->arg(0)->exprType() == INT_EXPR) {
177 int id = args->arg(0)->asInt()->evalInt();
178 if (id < 0) {
179 wrnMsg("note_off(): argument 1 may not be a negative event ID");
180 return successResult();
181 }
182
183 RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(id);
184 if (!itEvent) return successResult();
185
186 Event e = *itEvent;
187 e.Type = Event::type_note_off;
188 e.Param.Note.Velocity = velocity;
189 memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero
190
191 int releaseEventID = pEngineChannel->ScheduleEventMicroSec(&e, 0);
192 } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
193 VMIntArrayExpr* ids = args->arg(0)->asIntArray();
194 for (int i = 0; i < ids->arraySize(); ++i) {
195 int id = ids->evalIntElement(i);
196
197 RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(id);
198 if (!itEvent) continue;
199
200 Event e = *itEvent;
201 e.Type = Event::type_note_off;
202 e.Param.Note.Velocity = velocity;
203 memset(&e.Format, 0, sizeof(e.Format)); // init format speific stuff with zero
204
205 int releaseEventID = pEngineChannel->ScheduleEventMicroSec(&e, 0);
206 }
207 }
208
209 return successResult();
210 }
211
212 InstrumentScriptVMFunction_set_event_mark::InstrumentScriptVMFunction_set_event_mark(InstrumentScriptVM* parent)
213 : m_vm(parent)
214 {
215 }
216
217 VMFnResult* InstrumentScriptVMFunction_set_event_mark::exec(VMFnArgs* args) {
218 int eventID = args->arg(0)->asInt()->evalInt();
219 int groupID = args->arg(1)->asInt()->evalInt();
220
221 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
222 errMsg("set_event_mark(): argument 2 is an invalid group id");
223 return errorResult();
224 }
225
226 AbstractEngineChannel* pEngineChannel =
227 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
228
229 RTList<Event>::Iterator itEvent = pEngineChannel->pEngine->EventByID(eventID);
230 if (!itEvent) return successResult();
231
232 pEngineChannel->pScript->eventGroups[groupID].insert(eventID);
233
234 return successResult();
235 }
236
237 InstrumentScriptVMFunction_delete_event_mark::InstrumentScriptVMFunction_delete_event_mark(InstrumentScriptVM* parent)
238 : m_vm(parent)
239 {
240 }
241
242 VMFnResult* InstrumentScriptVMFunction_delete_event_mark::exec(VMFnArgs* args) {
243 int eventID = args->arg(0)->asInt()->evalInt();
244 int groupID = args->arg(1)->asInt()->evalInt();
245
246 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
247 errMsg("delete_event_mark(): argument 2 is an invalid group id");
248 return errorResult();
249 }
250
251 AbstractEngineChannel* pEngineChannel =
252 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
253
254 pEngineChannel->pScript->eventGroups[groupID].erase(eventID);
255
256 return successResult();
257 }
258
259 InstrumentScriptVMFunction_by_marks::InstrumentScriptVMFunction_by_marks(InstrumentScriptVM* parent)
260 : m_vm(parent)
261 {
262 }
263
264 int InstrumentScriptVMFunction_by_marks::Result::arraySize() const {
265 return eventGroup->size();
266 }
267
268 int InstrumentScriptVMFunction_by_marks::Result::evalIntElement(uint i) {
269 return (*eventGroup)[i];
270 }
271
272 VMFnResult* InstrumentScriptVMFunction_by_marks::errorResult() {
273 m_result.eventGroup = NULL;
274 m_result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
275 return &m_result;
276 }
277
278 VMFnResult* InstrumentScriptVMFunction_by_marks::successResult(EventGroup* eventGroup) {
279 m_result.eventGroup = eventGroup;
280 m_result.flags = STMT_SUCCESS;
281 return &m_result;
282 }
283
284 VMFnResult* InstrumentScriptVMFunction_by_marks::exec(VMFnArgs* args) {
285 int groupID = args->arg(0)->asInt()->evalInt();
286
287 if (groupID < 0 || groupID >= INSTR_SCRIPT_EVENT_GROUPS) {
288 errMsg("by_marks(): argument is an invalid group id");
289 return errorResult();
290 }
291
292 AbstractEngineChannel* pEngineChannel =
293 static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
294
295 return successResult( &pEngineChannel->pScript->eventGroups[groupID] );
296 }
297
298 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC