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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2594 - (hide 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 schoenebeck 2581 /*
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 schoenebeck 2588 #include <string.h>
13 schoenebeck 2581 #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 schoenebeck 2588 ScriptVM::ScriptVM() : m_parserContext(NULL), fnWait(this) {
92 schoenebeck 2581 }
93    
94     ScriptVM::~ScriptVM() {
95     }
96    
97 schoenebeck 2588 VMParserContext* ScriptVM::loadScript(const String& s) {
98 schoenebeck 2581 std::istringstream iss(s);
99 schoenebeck 2588 return loadScript(&iss);
100 schoenebeck 2581 }
101    
102 schoenebeck 2588 VMParserContext* ScriptVM::loadScript(std::istream* is) {
103     ParserContext* context = new ParserContext(this);
104     //printf("parserCtx=0x%lx\n", (uint64_t)context);
105 schoenebeck 2594
106     context->registerBuiltInConstIntVariables( builtInConstIntVariables() );
107     context->registerBuiltInIntVariables( builtInIntVariables() );
108     context->registerBuiltInIntArrayVariables( builtInIntArrayVariables() );
109    
110 schoenebeck 2588 context->createScanner(is);
111 schoenebeck 2581
112 schoenebeck 2588 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 schoenebeck 2581
124 schoenebeck 2588 context->destroyScanner();
125 schoenebeck 2581
126 schoenebeck 2588 return context;
127 schoenebeck 2581 }
128    
129 schoenebeck 2588 void ScriptVM::dumpParsedScript(VMParserContext* context) {
130     ParserContext* ctx = dynamic_cast<ParserContext*>(context);
131     if (!ctx) {
132 schoenebeck 2581 std::cerr << "No VM context. So nothing to dump.\n";
133     return;
134     }
135 schoenebeck 2588 if (!ctx->handlers) {
136 schoenebeck 2581 std::cerr << "No event handlers defined in script. So nothing to dump.\n";
137     return;
138     }
139 schoenebeck 2588 if (!ctx->globalIntMemory) {
140 schoenebeck 2581 std::cerr << "Internal error: no global memory assigend to script VM.\n";
141     return;
142     }
143 schoenebeck 2588 ctx->handlers->dump();
144 schoenebeck 2581 }
145    
146 schoenebeck 2588 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 schoenebeck 2581 std::cout << "Created VM exec context with "
156 schoenebeck 2588 << parserCtx->requiredMaxStackSize * sizeof(ExecContext::StackFrame)
157 schoenebeck 2581 << " bytes VM stack size.\n";
158 schoenebeck 2588 //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 schoenebeck 2581 std::cout << "Allocated " << polySize * sizeof(int)
164     << " bytes polyphonic memory.\n";
165 schoenebeck 2588 return execCtx;
166 schoenebeck 2581 }
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 schoenebeck 2588
175 schoenebeck 2594 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 schoenebeck 2588 VMParserContext* ScriptVM::currentVMParserContext() {
188     return m_parserContext;
189     }
190    
191 schoenebeck 2581 VMExecContext* ScriptVM::currentVMExecContext() {
192 schoenebeck 2588 if (!m_parserContext) return NULL;
193     return m_parserContext->execContext;
194 schoenebeck 2581 }
195    
196 schoenebeck 2588 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 schoenebeck 2581 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 schoenebeck 2588 m_parserContext->execContext = ctx;
212 schoenebeck 2581
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 schoenebeck 2588 m_parserContext->execContext = NULL;
306     m_parserContext = NULL;
307 schoenebeck 2581 return ctx->status;
308     }
309    
310     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC