You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
6.0KB

  1. #include "ScriptEngine.hpp"
  2. #include <duktape.h>
  3. struct DuktapeEngine : ScriptEngine {
  4. duk_context* ctx = NULL;
  5. ~DuktapeEngine() {
  6. if (ctx)
  7. duk_destroy_heap(ctx);
  8. }
  9. std::string getEngineName() override {
  10. return "JavaScript";
  11. }
  12. int run(const std::string& path, const std::string& script) override {
  13. assert(!ctx);
  14. ProcessBlock* block = getProcessBlock();
  15. // Create duktape context
  16. ctx = duk_create_heap_default();
  17. if (!ctx) {
  18. display("Could not create duktape context");
  19. return -1;
  20. }
  21. // Initialize globals
  22. // user pointer
  23. duk_push_pointer(ctx, this);
  24. duk_put_global_string(ctx, DUK_HIDDEN_SYMBOL("engine"));
  25. // console
  26. duk_idx_t consoleIdx = duk_push_object(ctx);
  27. {
  28. // log
  29. duk_push_c_function(ctx, native_console_log, 1);
  30. duk_put_prop_string(ctx, consoleIdx, "log");
  31. }
  32. duk_put_global_string(ctx, "console");
  33. // display
  34. duk_push_c_function(ctx, native_display, 1);
  35. duk_put_global_string(ctx, "display");
  36. // config: Set defaults
  37. duk_idx_t configIdx = duk_push_object(ctx);
  38. {
  39. // frameDivider
  40. duk_push_int(ctx, 32);
  41. duk_put_prop_string(ctx, configIdx, "frameDivider");
  42. // bufferSize
  43. duk_push_int(ctx, 1);
  44. duk_put_prop_string(ctx, configIdx, "bufferSize");
  45. }
  46. duk_put_global_string(ctx, "config");
  47. // Compile string
  48. duk_push_string(ctx, path.c_str());
  49. if (duk_pcompile_lstring_filename(ctx, 0, script.c_str(), script.size()) != 0) {
  50. const char* s = duk_safe_to_string(ctx, -1);
  51. WARN("duktape: %s", s);
  52. display(s);
  53. duk_pop(ctx);
  54. return -1;
  55. }
  56. // Execute function
  57. if (duk_pcall(ctx, 0)) {
  58. const char* s = duk_safe_to_string(ctx, -1);
  59. WARN("duktape: %s", s);
  60. display(s);
  61. duk_pop(ctx);
  62. return -1;
  63. }
  64. // Ignore return value
  65. duk_pop(ctx);
  66. // config: Read values
  67. duk_get_global_string(ctx, "config");
  68. {
  69. // frameDivider
  70. duk_get_prop_string(ctx, -1, "frameDivider");
  71. setFrameDivider(duk_get_int(ctx, -1));
  72. duk_pop(ctx);
  73. // bufferSize
  74. duk_get_prop_string(ctx, -1, "bufferSize");
  75. setBufferSize(duk_get_int(ctx, -1));
  76. duk_pop(ctx);
  77. }
  78. duk_pop(ctx);
  79. // Keep process function on stack for faster calling
  80. duk_get_global_string(ctx, "process");
  81. if (!duk_is_function(ctx, -1)) {
  82. display("No process() function");
  83. return -1;
  84. }
  85. // block (keep on stack)
  86. duk_idx_t blockIdx = duk_push_object(ctx);
  87. {
  88. // inputs
  89. duk_idx_t inputsIdx = duk_push_array(ctx);
  90. for (int i = 0; i < NUM_ROWS; i++) {
  91. duk_push_external_buffer(ctx);
  92. duk_config_buffer(ctx, -1, block->inputs[i], sizeof(float) * block->bufferSize);
  93. duk_push_buffer_object(ctx, -1, 0, sizeof(float) * block->bufferSize, DUK_BUFOBJ_FLOAT32ARRAY);
  94. duk_put_prop_index(ctx, inputsIdx, i);
  95. duk_pop(ctx);
  96. }
  97. duk_put_prop_string(ctx, blockIdx, "inputs");
  98. // outputs
  99. duk_idx_t outputsIdx = duk_push_array(ctx);
  100. for (int i = 0; i < NUM_ROWS; i++) {
  101. duk_push_external_buffer(ctx);
  102. duk_config_buffer(ctx, -1, block->outputs[i], sizeof(float) * block->bufferSize);
  103. duk_push_buffer_object(ctx, -1, 0, sizeof(float) * block->bufferSize, DUK_BUFOBJ_FLOAT32ARRAY);
  104. duk_put_prop_index(ctx, outputsIdx, i);
  105. duk_pop(ctx);
  106. }
  107. duk_put_prop_string(ctx, blockIdx, "outputs");
  108. // knobs
  109. duk_push_external_buffer(ctx);
  110. duk_config_buffer(ctx, -1, block->knobs, sizeof(float) * NUM_ROWS);
  111. duk_push_buffer_object(ctx, -1, 0, sizeof(float) * NUM_ROWS, DUK_BUFOBJ_FLOAT32ARRAY);
  112. duk_put_prop_string(ctx, blockIdx, "knobs");
  113. duk_pop(ctx);
  114. // switches
  115. duk_push_external_buffer(ctx);
  116. duk_config_buffer(ctx, -1, block->switches, sizeof(bool) * NUM_ROWS);
  117. duk_push_buffer_object(ctx, -1, 0, sizeof(bool) * NUM_ROWS, DUK_BUFOBJ_UINT8ARRAY);
  118. duk_put_prop_string(ctx, blockIdx, "switches");
  119. duk_pop(ctx);
  120. // lights
  121. duk_idx_t lightsIdx = duk_push_array(ctx);
  122. for (int i = 0; i < NUM_ROWS; i++) {
  123. duk_push_external_buffer(ctx);
  124. duk_config_buffer(ctx, -1, block->lights[i], sizeof(float) * 3);
  125. duk_push_buffer_object(ctx, -1, 0, sizeof(float) * 3, DUK_BUFOBJ_FLOAT32ARRAY);
  126. duk_put_prop_index(ctx, lightsIdx, i);
  127. duk_pop(ctx);
  128. }
  129. duk_put_prop_string(ctx, blockIdx, "lights");
  130. // switchLights
  131. duk_idx_t switchLightsIdx = duk_push_array(ctx);
  132. for (int i = 0; i < NUM_ROWS; i++) {
  133. duk_push_external_buffer(ctx);
  134. duk_config_buffer(ctx, -1, block->switchLights[i], sizeof(float) * 3);
  135. duk_push_buffer_object(ctx, -1, 0, sizeof(float) * 3, DUK_BUFOBJ_FLOAT32ARRAY);
  136. duk_put_prop_index(ctx, switchLightsIdx, i);
  137. duk_pop(ctx);
  138. }
  139. duk_put_prop_string(ctx, blockIdx, "switchLights");
  140. }
  141. return 0;
  142. }
  143. int process() override {
  144. // block
  145. ProcessBlock* block = getProcessBlock();
  146. duk_idx_t blockIdx = duk_get_top(ctx) - 1;
  147. {
  148. // sampleRate
  149. duk_push_number(ctx, block->sampleRate);
  150. duk_put_prop_string(ctx, blockIdx, "sampleRate");
  151. // sampleTime
  152. duk_push_number(ctx, block->sampleTime);
  153. duk_put_prop_string(ctx, blockIdx, "sampleTime");
  154. // bufferSize
  155. duk_push_int(ctx, block->bufferSize);
  156. duk_put_prop_string(ctx, blockIdx, "bufferSize");
  157. }
  158. // Duplicate process function
  159. duk_dup(ctx, -2);
  160. // Duplicate block object
  161. duk_dup(ctx, -2);
  162. // Call process function
  163. if (duk_pcall(ctx, 1)) {
  164. const char* s = duk_safe_to_string(ctx, -1);
  165. WARN("duktape: %s", s);
  166. display(s);
  167. duk_pop(ctx);
  168. return -1;
  169. }
  170. // return value
  171. duk_pop(ctx);
  172. return 0;
  173. }
  174. static DuktapeEngine* getDuktapeEngine(duk_context* ctx) {
  175. duk_get_global_string(ctx, DUK_HIDDEN_SYMBOL("engine"));
  176. DuktapeEngine* engine = (DuktapeEngine*) duk_get_pointer(ctx, -1);
  177. duk_pop(ctx);
  178. return engine;
  179. }
  180. static duk_ret_t native_console_log(duk_context* ctx) {
  181. const char* s = duk_safe_to_string(ctx, -1);
  182. INFO("Duktape: %s", s);
  183. return 0;
  184. }
  185. static duk_ret_t native_display(duk_context* ctx) {
  186. const char* s = duk_safe_to_string(ctx, -1);
  187. getDuktapeEngine(ctx)->display(s);
  188. return 0;
  189. }
  190. };
  191. __attribute__((constructor(1000)))
  192. static void constructor() {
  193. addScriptEngine<DuktapeEngine>("js");
  194. }