1 |
|
---|
2 |
|
---|
3 | var JSDynamicMixMeandreWorkflow = function() {
|
---|
4 |
|
---|
5 | var domain_prefix = window.location.protocol + "//" + window.location.hostname;
|
---|
6 |
|
---|
7 | this.meandreController = new MeandreController(domain_prefix,"1714","1712");
|
---|
8 |
|
---|
9 | this.baseURI = "http://greenstone.org/meandre/flows/dynamic-javascript-mixer/"
|
---|
10 | this.serviceHead = this.baseURI + "instance/greenstone-audio-web-service-head/0";
|
---|
11 | this.serviceTail = this.baseURI + "instance/float32-frame-web-service-buffer/3";
|
---|
12 |
|
---|
13 | this.serviceJSDynamic = this.baseURI + "instance/dynamic-javascript-computation-component/2";
|
---|
14 |
|
---|
15 | this.flowPort = null;
|
---|
16 |
|
---|
17 | this.meandreFrameSize = null;
|
---|
18 | this.meandreDataOutput = new Array();
|
---|
19 |
|
---|
20 | this.meandreCount = 0;
|
---|
21 | }
|
---|
22 |
|
---|
23 |
|
---|
24 | JSDynamicMixMeandreWorkflow.prototype.thisMeandreFlowIsRunning = function() {
|
---|
25 | return this.flowPort != null;
|
---|
26 | }
|
---|
27 |
|
---|
28 | function bin2String(array,range) {
|
---|
29 | var result = "";
|
---|
30 |
|
---|
31 | var excerpt = range || 5000;
|
---|
32 |
|
---|
33 | var lowcut = Math.min(array.length,excerpt);
|
---|
34 |
|
---|
35 | result += "low cut: " + lowcut + "\n";
|
---|
36 | for (var i = 0; i < lowcut; i++) {
|
---|
37 | result += String.fromCharCode(65+array[i]);
|
---|
38 | if (((i+1)%200)==0) {
|
---|
39 | result += "\n";
|
---|
40 | }
|
---|
41 | }
|
---|
42 |
|
---|
43 | result += "\n";
|
---|
44 |
|
---|
45 |
|
---|
46 | var highcut = Math.max(array.length-excerpt,0);
|
---|
47 | result += "high cut: " + highcut + "\n";
|
---|
48 |
|
---|
49 | for (var i = highcut; i < array.length; i++) {
|
---|
50 | result += String.fromCharCode(65+array[i]);
|
---|
51 | if (((i+1)%200)==0) {
|
---|
52 | result += "\n";
|
---|
53 | }
|
---|
54 | }
|
---|
55 | result += "\n";
|
---|
56 |
|
---|
57 | return result;
|
---|
58 | }
|
---|
59 |
|
---|
60 | JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputDataCallback = function(oEvent,oReq) {
|
---|
61 |
|
---|
62 |
|
---|
63 | var arrayBuffer = oReq.response; // Note: not oReq.responseText
|
---|
64 |
|
---|
65 | if (arrayBuffer.byteLength) {
|
---|
66 | //console.log("*** get-data callback: Recieved binary data: raw byte array buffer len = " + arrayBuffer.byteLength);
|
---|
67 |
|
---|
68 | //console.log("*** type of arrayBuffer: " + toType(arrayBuffer));
|
---|
69 |
|
---|
70 | //var float32Array = new Float32Array(arrayBuffer);
|
---|
71 | var byteArray = new Uint8Array(arrayBuffer);
|
---|
72 | var byteArrayLen = byteArray.length;
|
---|
73 |
|
---|
74 | var fixPos = new Array();
|
---|
75 | for (var i=0; i<byteArrayLen; i++) {
|
---|
76 | if ((byteArray[i]==10)) {
|
---|
77 | // && ((i<byteArrayLen-1) && (byteArray[i+1]==13))) {
|
---|
78 | // Despite the 'response' from the servlet being set to content type 'application/octet'
|
---|
79 | // the output streamed through the server is still treated as text, and a '10' in the binary
|
---|
80 | // stream is changed to '13', '10'
|
---|
81 |
|
---|
82 | fixPos.push(i-1);
|
---|
83 | }
|
---|
84 | }
|
---|
85 |
|
---|
86 | var fixPosLen = fixPos.length;
|
---|
87 | //console.log("*** fix pos len = " + fixPosLen);
|
---|
88 |
|
---|
89 | var fixedByteArrayLen = byteArrayLen - fixPosLen;
|
---|
90 | var fixedByteArray = new Uint8Array(fixedByteArrayLen);
|
---|
91 |
|
---|
92 | var prevPos = 0;
|
---|
93 | var newPos = 0;
|
---|
94 |
|
---|
95 | for (var i=0; i<fixPosLen; i++) {
|
---|
96 | var currFixPos = fixPos[i];
|
---|
97 |
|
---|
98 | var sliceArray = byteArray.subarray(prevPos,currFixPos);
|
---|
99 | fixedByteArray.set(sliceArray,newPos);
|
---|
100 |
|
---|
101 | prevPos = currFixPos+1; // shift over erroneous <CR> (char 13)
|
---|
102 | newPos += sliceArray.length;
|
---|
103 |
|
---|
104 | }
|
---|
105 |
|
---|
106 | var remainingSliceArray = byteArray.subarray(prevPos);
|
---|
107 | fixedByteArray.set(remainingSliceArray,newPos);
|
---|
108 |
|
---|
109 | if ((fixedByteArray.length % 4) != 0) {
|
---|
110 | console.error("Fixed Returned binary data is not a multiple of 4");
|
---|
111 |
|
---|
112 | this.meandreDataOutput.push(byteArray);
|
---|
113 | }
|
---|
114 | else {
|
---|
115 | //console.log("fixed byte array len = " + fixedByteArray.length);
|
---|
116 |
|
---|
117 | var float32Array = new Float32Array(fixedByteArray.buffer);
|
---|
118 |
|
---|
119 | //console.log("float array len = " + float32Array.length);
|
---|
120 |
|
---|
121 | var meandreFrameSize = this.meandreFrameSize;
|
---|
122 | var numFramesReceived = float32Array.length/meandreFrameSize;
|
---|
123 |
|
---|
124 | //console.log("** meandre output frameSize = " + meandreFrameSize);
|
---|
125 | console.info("*** get-data callback: number of frames received = " + numFramesReceived);
|
---|
126 |
|
---|
127 | for (var i=0; i<numFramesReceived; i++) {
|
---|
128 | var startPos = i*meandreFrameSize;
|
---|
129 | var endPos = startPos + meandreFrameSize -1;
|
---|
130 | var frame = float32Array.subarray(startPos,endPos);
|
---|
131 |
|
---|
132 | //console.log("*** frameSize=" + meandreFrameSize + ", start pos=" + startPos + ", endPos=" + endPos + ", pushing on frame of size: " + frame.length);
|
---|
133 |
|
---|
134 | this.meandreDataOutput.push(frame);
|
---|
135 | }
|
---|
136 | }
|
---|
137 | }
|
---|
138 | }
|
---|
139 |
|
---|
140 |
|
---|
141 |
|
---|
142 | JSDynamicMixMeandreWorkflow.prototype.processThisMeandreFlowOutputData = function(flowPort) {
|
---|
143 |
|
---|
144 | // does flowPort need to be passed in as a parameter, now this is method not a function?
|
---|
145 |
|
---|
146 | var getinfo_options = {cmd: "get-info" };
|
---|
147 |
|
---|
148 | var info_props = this.meandreController.webComponentProperties(flowPort,this.serviceTail,getinfo_options)
|
---|
149 |
|
---|
150 | // values stored in 'info_props' are strings => need to make sure we treat get numeric fields such
|
---|
151 | // as 'numFrames' as an integer
|
---|
152 |
|
---|
153 | var numFramesAvailable = parseInt(info_props.numFrames);
|
---|
154 | if (isDefined(numFramesAvailable)) {
|
---|
155 | this.meandreFrameSize = parseInt(info_props.frameSize);
|
---|
156 | }
|
---|
157 | else {
|
---|
158 | numFramesAvailable = 0;
|
---|
159 | }
|
---|
160 |
|
---|
161 | // console.log("*** Meandre count = " + meandreCount);
|
---|
162 |
|
---|
163 | if (numFramesAvailable>0) {
|
---|
164 |
|
---|
165 | var getNumFrames = Math.min(600,numFramesAvailable);
|
---|
166 |
|
---|
167 | console.info("get-data request: Number of frames available = " + numFramesAvailable, ", number of frames requested = " + getNumFrames);
|
---|
168 |
|
---|
169 | // console.log("***** doing a get-data");
|
---|
170 | var getdata_options = {cmd: "get-data", numFrames: getNumFrames };
|
---|
171 | var payload = this.meandreController.binaryWebComponent(flowPort,this.serviceTail,getdata_options,
|
---|
172 | this.processThisMeandreFlowOutputDataCallback,this);
|
---|
173 |
|
---|
174 | // delay the next call to 'get-info' to give the 'get-data' a chance to reach the server
|
---|
175 | var that = this;
|
---|
176 | setTimeout(function() {
|
---|
177 | that.processThisMeandreFlowOutputData(flowPort);
|
---|
178 | }, 800);
|
---|
179 |
|
---|
180 | }
|
---|
181 | else {
|
---|
182 | console.log("*** Sending 'done' command");
|
---|
183 | var done_options = {cmd: "done" };
|
---|
184 | this.meandreController.webComponent(flowPort,this.serviceHead,done_options);
|
---|
185 |
|
---|
186 | // disable 'stop' and make 'run' active again
|
---|
187 | $('#meandre-stop-button').attr("disabled", "disabled");
|
---|
188 | $('#meandre-run-button').removeAttr("disabled");
|
---|
189 | }
|
---|
190 |
|
---|
191 | this.meandreCount++;
|
---|
192 | }
|
---|
193 |
|
---|
194 |
|
---|
195 | JSDynamicMixMeandreWorkflow.prototype.runThisMeandreFlow = function(elem,playCallback) {
|
---|
196 |
|
---|
197 | if (this.thisMeandreFlowIsRunning()) {
|
---|
198 | console.error("runThisMeandreFlow(): The flow is already running on port " + this.flowPort);
|
---|
199 | return;
|
---|
200 | }
|
---|
201 |
|
---|
202 | var $progressElem = $('#processing');
|
---|
203 | var $progressTitleElem = $('#processingTitle');
|
---|
204 | var $progressTextElem = $('#processingText');
|
---|
205 |
|
---|
206 | var displayProgress = ($progressElem.length>0) ? true : false;
|
---|
207 | if (displayProgress) {
|
---|
208 | $progressTitleElem.html("Starting Meandre Workflow ...");
|
---|
209 | $progressTextElem.css('display','none');
|
---|
210 | $progressElem.css('display','block');
|
---|
211 | }
|
---|
212 |
|
---|
213 |
|
---|
214 | var flow_token = this.meandreController.runFlow(this.baseURI);
|
---|
215 | //console.log("**** got flow token : " + flow_token);
|
---|
216 |
|
---|
217 | // Give the flow time to start up ...
|
---|
218 | var that = this;
|
---|
219 | setTimeout(function() {
|
---|
220 | // Now find out which port it is running on ...
|
---|
221 | var flow_props = that.meandreController.runningFlowProperties(flow_token);
|
---|
222 | var flow_port = flow_props.port;
|
---|
223 |
|
---|
224 | var attempts = 0;
|
---|
225 | while ((flow_port==null) || (flow_port <= 0)) {
|
---|
226 | console.info("port returned as " + flow_port + ", trying again");
|
---|
227 | flow_props = that.meandreController.runningFlowProperties(flow_token);
|
---|
228 | flow_port = flow_props.port;
|
---|
229 | attempts++;
|
---|
230 |
|
---|
231 | if (attempts==10) {
|
---|
232 | break;
|
---|
233 | }
|
---|
234 | }
|
---|
235 |
|
---|
236 | console.info("Running Meandre flow on port : " + flow_port);
|
---|
237 | that.flowPort = flow_port;
|
---|
238 |
|
---|
239 | $('#meandre-run-button').attr("disabled", "disabled");
|
---|
240 | $('#meandre-stop-button').removeAttr("disabled");
|
---|
241 |
|
---|
242 | //$('#meandre-run-button').button({ disabled: true });
|
---|
243 | //$('#meandre-stop-button').button({disabled: false});
|
---|
244 |
|
---|
245 |
|
---|
246 | // send over the user's custom javascript
|
---|
247 | var script_str = $("#js-dynamic-code").val();
|
---|
248 |
|
---|
249 | var script_options = {
|
---|
250 | code: encodeURIComponent(script_str) // effectively double encode to get it through the proxy-server
|
---|
251 | };
|
---|
252 |
|
---|
253 | that.meandreController.webComponent(that.flowPort,that.serviceJSDynamic,script_options);
|
---|
254 |
|
---|
255 |
|
---|
256 | var start_options = {
|
---|
257 | cmd: "generate-audio-signal",
|
---|
258 | docOID: "wibble",
|
---|
259 | site: gs.xsltParams["site_name"],
|
---|
260 | collect: collect,
|
---|
261 | assocPath: gs.documentMetadata["assocfilepath"],
|
---|
262 | assocFile: "doc.wav"
|
---|
263 | };
|
---|
264 |
|
---|
265 | that.meandreController.webComponent(that.flowPort,that.serviceHead,start_options);
|
---|
266 |
|
---|
267 | setTimeout(function() {
|
---|
268 | that.processThisMeandreFlowOutputData(that.flowPort);
|
---|
269 |
|
---|
270 | if (displayProgress) {
|
---|
271 | $progressElem.css('display','none');
|
---|
272 | $progressTextElem.css('display','block');
|
---|
273 | }
|
---|
274 |
|
---|
275 | if (elem!=null) {
|
---|
276 | // runFlow has been triggered by clicking on the 'run' button
|
---|
277 | togglePlay(null,document.getElementById('mainPlayButton'));
|
---|
278 | }
|
---|
279 | else if (playCallback!=null) {
|
---|
280 | playCallback();
|
---|
281 | }
|
---|
282 |
|
---|
283 | }, 800);
|
---|
284 |
|
---|
285 | }, 800);
|
---|
286 | }
|
---|
287 |
|
---|
288 | JSDynamicMixMeandreWorkflow.prototype.stopThisMeandreFlow = function(elem) {
|
---|
289 |
|
---|
290 | this.meandreController.abortFlow(this.flowPort);
|
---|
291 |
|
---|
292 | $('#meandre-stop-button').attr("disabled", "disabled");
|
---|
293 | $('#meandre-run-button').removeAttr("disabled");
|
---|
294 |
|
---|
295 | //$('#meandre-run-button').button({ disabled: false });
|
---|
296 | //$('#meandre-stop-button').button({disabled: true});
|
---|
297 | }
|
---|
298 |
|
---|