/[svn]/linuxsampler/trunk/src/scriptvm/ScriptVM.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/scriptvm/ScriptVM.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2594 - (show annotations) (download)
Thu Jun 5 00:16:25 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 11192 byte(s)
* ScriptVM (WIP): started to integrate real-time instrument script
  support into the sampler engine implementations. The code is
  shared among all sampler engines, however currently only the gig
  file format supports storing instrument scripts (as LinuxSampler
  extension to the original GigaStudio 4 file format).
* gig engine: Added support for loading instrument scripts from .gig
  files.
* ScriptVM (WIP): Implemented built-in script variables %CC, $CC_NUM,
  $EVENT_NOTE, $EVENT_VELOCITY, $VCC_MONO_AT, $VCC_PITCH_BEND.
* ScriptVM (WIP): Implemented execution of script event handler "init".
* ScriptVM (WIP): Implemented execution of script event handler
  "controller".
* Bumped version (1.0.0.svn42).

1 /*
2 * Copyright (c) 2014 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 "ScriptVM.h"
11
12 #include <string.h>
13 #include "../common/global_private.h"
14 #include "tree.h"
15
16 #define DEBUG_SCRIPTVM_CORE 0
17
18 int InstrScript_parse(LinuxSampler::ParserContext*);
19
20 namespace LinuxSampler {
21
22 static void _printIndents(int n) {
23 for (int i = 0; i < n; ++i) printf(" ");
24 fflush(stdout);
25 }
26
27 static int _requiredMaxStackSizeFor(Statement* statement, int depth = 0) {
28 if (!statement) return 1;
29
30 switch (statement->statementType()) {
31 case STMT_LEAF:
32 #if DEBUG_SCRIPTVM_CORE
33 _printIndents(depth);
34 printf("-> STMT_LEAF\n");
35 #endif
36 return 1;
37
38 case STMT_LIST: {
39 #if DEBUG_SCRIPTVM_CORE
40 _printIndents(depth);
41 printf("-> STMT_LIST\n");
42 #endif
43 Statements* stmts = (Statements*) statement;
44 int max = 0;
45 for (int i = 0; stmts->statement(i); ++i) {
46 int size = _requiredMaxStackSizeFor( stmts->statement(i), depth+1 );
47 if (max < size) max = size;
48 }
49 return max + 1;
50 }
51
52 case STMT_BRANCH: {
53 #if DEBUG_SCRIPTVM_CORE
54 _printIndents(depth);
55 printf("-> STMT_BRANCH\n");
56 #endif
57 BranchStatement* branchStmt = (BranchStatement*) statement;
58 int max = 0;
59 for (int i = 0; branchStmt->branch(i); ++i) {
60 int size = _requiredMaxStackSizeFor( branchStmt->branch(i), depth+1 );
61 if (max < size) max = size;
62 }
63 return max + 1;
64 }
65
66 case STMT_LOOP: {
67 #if DEBUG_SCRIPTVM_CORE
68 _printIndents(depth);
69 printf("-> STMT_LOOP\n");
70 #endif
71 While* whileStmt = (While*) statement;
72 if (whileStmt->statements())
73 return _requiredMaxStackSizeFor( whileStmt->statements() ) + 1;
74 else
75 return 1;
76 }
77 }
78
79 return 1; // actually just to avoid compiler warning
80 }
81
82 static int _requiredMaxStackSizeFor(EventHandlers* handlers) {
83 int max = 1;
84 for (int i = 0; i < handlers->size(); ++i) {
85 int size = _requiredMaxStackSizeFor(handlers->eventHandler(i));
86 if (max < size) max = size;
87 }
88 return max;
89 }
90
91 ScriptVM::ScriptVM() : m_parserContext(NULL), fnWait(this) {
92 }
93
94 ScriptVM::~ScriptVM() {
95 }
96
97 VMParserContext* ScriptVM::loadScript(const String& s) {
98 std::istringstream iss(s);
99 return loadScript(&iss);
100 }
101
102 VMParserContext* ScriptVM::loadScript(std::istream* is) {
103 ParserContext* context = new ParserContext(this);
104 //printf("parserCtx=0x%lx\n", (uint64_t)context);
105
106 context->registerBuiltInConstIntVariables( builtInConstIntVariables() );
107 context->registerBuiltInIntVariables( builtInIntVariables() );
108 context->registerBuiltInIntArrayVariables( builtInIntArrayVariables() );
109
110 context->createScanner(is);
111
112 InstrScript_parse(context);
113 std::cout << "Allocating " << context->globalIntVarCount * sizeof(int) << " bytes of global int VM memory.\n";
114 std::cout << "Allocating " << context->globalStrVarCount << " of global VM string variables.\n";
115 if (!context->globalIntMemory)
116 context->globalIntMemory = new ArrayList<int>();
117 if (!context->globalStrMemory)
118 context->globalStrMemory = new ArrayList<String>();
119 context->globalIntMemory->resize(context->globalIntVarCount);
120 memset(&((*context->globalIntMemory)[0]), 0, context->globalIntVarCount * sizeof(int));
121
122 context->globalStrMemory->resize(context->globalStrVarCount);
123
124 context->destroyScanner();
125
126 return context;
127 }
128
129 void ScriptVM::dumpParsedScript(VMParserContext* context) {
130 ParserContext* ctx = dynamic_cast<ParserContext*>(context);
131 if (!ctx) {
132 std::cerr << "No VM context. So nothing to dump.\n";
133 return;
134 }
135 if (!ctx->handlers) {
136 std::cerr << "No event handlers defined in script. So nothing to dump.\n";
137 return;
138 }
139 if (!ctx->globalIntMemory) {
140 std::cerr << "Internal error: no global memory assigend to script VM.\n";
141 return;
142 }
143 ctx->handlers->dump();
144 }
145
146 VMExecContext* ScriptVM::createExecContext(VMParserContext* parserContext) {
147 ParserContext* parserCtx = dynamic_cast<ParserContext*>(parserContext);
148 ExecContext* execCtx = new ExecContext();
149
150 if (parserCtx->requiredMaxStackSize < 0) {
151 parserCtx->requiredMaxStackSize =
152 _requiredMaxStackSizeFor(&*parserCtx->handlers);
153 }
154 execCtx->stack.resize(parserCtx->requiredMaxStackSize);
155 std::cout << "Created VM exec context with "
156 << parserCtx->requiredMaxStackSize * sizeof(ExecContext::StackFrame)
157 << " bytes VM stack size.\n";
158 //printf("execCtx=0x%lx\n", (uint64_t)execCtx);
159 const int polySize = parserCtx->polyphonicIntVarCount;
160 execCtx->polyphonicIntMemory.resize(polySize);
161 memset(&execCtx->polyphonicIntMemory[0], 0, polySize * sizeof(int));
162
163 std::cout << "Allocated " << polySize * sizeof(int)
164 << " bytes polyphonic memory.\n";
165 return execCtx;
166 }
167
168 VMFunction* ScriptVM::functionByName(const String& name) {
169 if (name == "message") return &fnMessage;
170 else if (name == "exit") return &fnExit;
171 else if (name == "wait") return &fnWait;
172 return NULL;
173 }
174
175 std::map<String,VMIntRelPtr*> ScriptVM::builtInIntVariables() {
176 return std::map<String,VMIntRelPtr*>();
177 }
178
179 std::map<String,VMInt8Array*> ScriptVM::builtInIntArrayVariables() {
180 return std::map<String,VMInt8Array*>();
181 }
182
183 std::map<String,int> ScriptVM::builtInConstIntVariables() {
184 return std::map<String,int>();
185 }
186
187 VMParserContext* ScriptVM::currentVMParserContext() {
188 return m_parserContext;
189 }
190
191 VMExecContext* ScriptVM::currentVMExecContext() {
192 if (!m_parserContext) return NULL;
193 return m_parserContext->execContext;
194 }
195
196 VMExecStatus_t ScriptVM::exec(VMParserContext* parserContext, VMExecContext* execContex, VMEventHandler* handler) {
197 m_parserContext = dynamic_cast<ParserContext*>(parserContext);
198 if (!m_parserContext) {
199 std::cerr << "No VM parser context provided. Did you load a script?.\n";
200 return VMExecStatus_t(VM_EXEC_NOT_RUNNING | VM_EXEC_ERROR);
201 }
202
203 ExecContext* ctx = dynamic_cast<ExecContext*>(execContex);
204 if (!ctx) {
205 std::cerr << "Invalid VM exec context.\n";
206 return VMExecStatus_t(VM_EXEC_NOT_RUNNING | VM_EXEC_ERROR);
207 }
208 EventHandler* h = dynamic_cast<EventHandler*>(handler);
209 if (!h) return VM_EXEC_NOT_RUNNING;
210
211 m_parserContext->execContext = ctx;
212
213 ctx->status = VM_EXEC_RUNNING;
214 StmtFlags_t flags = STMT_SUCCESS;
215
216 int& frameIdx = ctx->stackFrame;
217 if (frameIdx < 0) { // start condition ...
218 frameIdx = -1;
219 ctx->pushStack(h);
220 }
221
222 while (flags == STMT_SUCCESS && frameIdx >= 0) {
223 if (frameIdx >= ctx->stack.size()) { // should never happen, otherwise it's a bug ...
224 std::cerr << "CRITICAL: VM stack overflow! (" << frameIdx << ")\n";
225 flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
226 break;
227 }
228
229 ExecContext::StackFrame& frame = ctx->stack[frameIdx];
230 switch (frame.statement->statementType()) {
231 case STMT_LEAF: {
232 #if DEBUG_SCRIPTVM_CORE
233 _printIndents(frameIdx);
234 printf("-> STMT_LEAF\n");
235 #endif
236 LeafStatement* leaf = (LeafStatement*) frame.statement;
237 flags = leaf->exec();
238 ctx->popStack();
239 break;
240 }
241
242 case STMT_LIST: {
243 #if DEBUG_SCRIPTVM_CORE
244 _printIndents(frameIdx);
245 printf("-> STMT_LIST subidx=%d\n", frame.subindex);
246 #endif
247 Statements* stmts = (Statements*) frame.statement;
248 if (stmts->statement(frame.subindex)) {
249 ctx->pushStack(
250 stmts->statement(frame.subindex++)
251 );
252 } else {
253 #if DEBUG_SCRIPTVM_CORE
254 _printIndents(frameIdx);
255 printf("[END OF LIST] subidx=%d\n", frame.subindex);
256 #endif
257 ctx->popStack();
258 }
259 break;
260 }
261
262 case STMT_BRANCH: {
263 #if DEBUG_SCRIPTVM_CORE
264 _printIndents(frameIdx);
265 printf("-> STMT_BRANCH\n");
266 #endif
267 if (frame.subindex < 0) ctx->popStack();
268 else {
269 BranchStatement* branchStmt = (BranchStatement*) frame.statement;
270 frame.subindex = branchStmt->evalBranch();
271 if (frame.subindex >= 0) {
272 ctx->pushStack(
273 branchStmt->branch(frame.subindex)
274 );
275 frame.subindex = -1;
276 } else ctx->popStack();
277 }
278 break;
279 }
280
281 case STMT_LOOP: {
282 #if DEBUG_SCRIPTVM_CORE
283 _printIndents(frameIdx);
284 printf("-> STMT_LOOP\n");
285 #endif
286 While* whileStmt = (While*) frame.statement;
287 if (whileStmt->evalLoopStartCondition() && whileStmt->statements()) {
288 ctx->pushStack(
289 whileStmt->statements()
290 );
291 } else ctx->popStack();
292 }
293 }
294 }
295
296 if (flags & STMT_SUSPEND_SIGNALLED) {
297 ctx->status = VM_EXEC_SUSPENDED;
298 } else {
299 ctx->status = VM_EXEC_NOT_RUNNING;
300 if (flags & STMT_ERROR_OCCURRED)
301 ctx->status = VM_EXEC_ERROR;
302 ctx->reset();
303 }
304
305 m_parserContext->execContext = NULL;
306 m_parserContext = NULL;
307 return ctx->status;
308 }
309
310 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC