1 /*
2 Copyright (C) 2008-2016 Andres Cabrera
3 mantaraya36@gmail.com
4
5 This file is part of CsoundQt.
6
7 CsoundQt is free software; you can redistribute it
8 and/or modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 CsoundQt is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with Csound; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA
21 */
22
23
24 // Code based partly on CsoundHtmlWrapper by Michael Gogins https://github.com/gogins/gogins.github.io/tree/master/csound_html5.
25 // This class must be safe against calling with a null or uninitialized CsoundEngine.
26
27 #include "csoundhtmlwrapper.h"
28 #include "csoundhtmlview.h"
29 #include <QApplication>
30 #include <QDebug>
31
CsoundHtmlWrapper(QObject * parent)32 CsoundHtmlWrapper::CsoundHtmlWrapper(QObject *parent) :
33 QObject(parent),
34 m_csoundEngine(nullptr),
35 message_callback(nullptr),
36 csoundHtmlView(nullptr)
37 {
38 }
39
setCsoundHtmlView(CsoundHtmlView * csoundHtmlView_)40 void CsoundHtmlWrapper::setCsoundHtmlView(CsoundHtmlView *csoundHtmlView_) {
41 csoundHtmlView = csoundHtmlView_;
42 }
43
44
getCsound()45 CSOUND *CsoundHtmlWrapper::getCsound()
46 {
47 if(!m_csoundEngine) {
48 return nullptr;
49 }
50 return m_csoundEngine->getCsound();
51 }
52
getThread()53 CsoundPerformanceThread *CsoundHtmlWrapper::getThread()
54 {
55 if(!m_csoundEngine) {
56 return nullptr;
57 }
58 return m_csoundEngine->getUserData()->perfThread;
59 }
60
getUserData()61 CsoundUserData *CsoundHtmlWrapper::getUserData()
62 {
63 if(!m_csoundEngine) {
64 return nullptr;
65 }
66 return m_csoundEngine->getUserData();
67 }
68
setCsoundEngine(CsoundEngine * csEngine)69 void CsoundHtmlWrapper::setCsoundEngine(CsoundEngine *csEngine)
70 {
71 m_csoundEngine = csEngine;
72 if (m_csoundEngine != nullptr) {
73 auto csound = m_csoundEngine->getCsound();
74 if (csound != nullptr) {
75 //TODO: Csound crashes later -- not sure why.
76 //csoundSetMessageCallback(csound, CsoundHtmlWrapper::csoundMessageCallback_);
77 }
78 }
79 }
80
compileCsd(const QString & filename)81 int CsoundHtmlWrapper::compileCsd(const QString &filename) {
82 if (!m_csoundEngine) {
83 return -1;
84 }
85 #if CS_APIVERSION>=4
86 return csoundCompileCsd(getCsound(), filename.toLocal8Bit());
87 #else
88 return csoundCompileCsd(getCsound(), filename.toLocal8Bit().data());
89 #endif
90 }
91
compileCsdText(const QString & text)92 int CsoundHtmlWrapper::compileCsdText(const QString &text) {
93 if (!m_csoundEngine) {
94 return -1;
95 }
96 return csoundCompileCsdText(getCsound(), text.toLocal8Bit());
97 }
98
compileOrc(const QString & text)99 int CsoundHtmlWrapper::compileOrc(const QString &text) {
100 if (!m_csoundEngine) {
101 return -1;
102 }
103 return csoundCompileOrc(getCsound(), text.toLocal8Bit());
104 }
105
evalCode(const QString & text)106 double CsoundHtmlWrapper::evalCode(const QString &text) {
107 if (!m_csoundEngine) {
108 return -1;
109 }
110 return csoundEvalCode(getCsound(), text.toLocal8Bit());
111 }
112
get0dBFS()113 double CsoundHtmlWrapper::get0dBFS() {
114 if (!m_csoundEngine) {
115 return -1;
116 }
117 return csoundGet0dBFS(getCsound());
118 }
119
getApiVersion()120 int CsoundHtmlWrapper::getApiVersion() {
121 if (!m_csoundEngine) {
122 return -1;
123 }
124 return csoundGetAPIVersion();
125 }
126
getControlChannel(const QString & name)127 double CsoundHtmlWrapper::getControlChannel(const QString &name) {
128 if (!m_csoundEngine) {
129 return -1;
130 }
131 int result = 0;
132 double value = csoundGetControlChannel(getCsound(), name.toLocal8Bit(), &result);
133 return value;
134 }
135
getCurrentTimeSamples()136 qint64 CsoundHtmlWrapper::getCurrentTimeSamples() { // FIXME: unknown type int64_t qint64
137 if (!m_csoundEngine) {
138 return -1;
139 }
140 return csoundGetCurrentTimeSamples(getCsound());
141 }
142
getEnv(const QString & name)143 QString CsoundHtmlWrapper::getEnv(const QString &name) { // not sure, if it works... test with setGlobalEnv
144 if (!m_csoundEngine) {
145 return QString();
146 }
147 return csoundGetEnv(getCsound(),name.toLocal8Bit());
148 }
149
getKsmps()150 int CsoundHtmlWrapper::getKsmps() {
151 if (!m_csoundEngine) {
152 return -1;
153 }
154 return csoundGetKsmps(getCsound());
155 }
156
getNchnls()157 int CsoundHtmlWrapper::getNchnls() {
158 if (!m_csoundEngine) {
159 return -1;
160 }
161 return csoundGetNchnls(getCsound());
162 }
163
getNchnlsInput()164 int CsoundHtmlWrapper::getNchnlsInput() {
165 if (!m_csoundEngine) {
166 return -1;
167 }
168 return csoundGetNchnlsInput(getCsound());
169 }
170
getOutputName()171 QString CsoundHtmlWrapper::getOutputName() {
172 if (!m_csoundEngine) {
173 return QString();
174 }
175 return QString(csoundGetOutputName(getCsound()));
176 }
177
getScoreOffsetSeconds()178 double CsoundHtmlWrapper::getScoreOffsetSeconds() {
179 if (!m_csoundEngine) {
180 return -1;
181 }
182 return csoundGetScoreOffsetSeconds(getCsound());
183 }
184
getScoreTime()185 double CsoundHtmlWrapper::getScoreTime() {
186 if (!m_csoundEngine) {
187 return -1;
188 }
189 return csoundGetScoreTime(getCsound());
190 }
191
getSr()192 int CsoundHtmlWrapper::getSr() {
193 if (!m_csoundEngine) {
194 return -1;
195 }
196 return csoundGetSr(getCsound());
197 }
198
getStringChannel(const QString & name)199 QString CsoundHtmlWrapper::getStringChannel(const QString &name) {
200 if (!m_csoundEngine) {
201 return QString();
202 }
203 char buffer[0x100];
204 csoundGetStringChannel(getCsound(),name.toLocal8Bit(), buffer);
205 return QString(buffer);
206 }
207
getVersion()208 int CsoundHtmlWrapper::getVersion() {
209 return csoundGetVersion();
210 }
211
isPlaying()212 bool CsoundHtmlWrapper::isPlaying() {
213 if (!m_csoundEngine) {
214 return false;
215 }
216 if (!getThread()) {
217 return false;
218 }
219 return (getThread()->GetStatus() == 0);
220 }
221
isScorePending()222 int CsoundHtmlWrapper::isScorePending() {
223 if (!m_csoundEngine) {
224 return -1;
225 }
226 return csoundIsScorePending(getCsound());
227 }
228
message(const QString & text)229 void CsoundHtmlWrapper::message(const QString &text) {
230 if (!m_csoundEngine) {
231 return;
232 }
233 qDebug() << text;
234 if (isPlaying()) {
235 csoundMessage(getCsound(), "%s", text.toLocal8Bit().constData());
236 }
237 }
238
perform()239 int CsoundHtmlWrapper::perform() {
240 if (!m_csoundEngine) {
241 return -1;
242 }
243 if (getThread()) {
244 qDebug() << "Stopping existing Csound performance thread.";
245 getThread()->Stop();
246 getThread()->Join();
247 delete getThread();
248 }
249 getUserData()->perfThread = new CsoundPerformanceThread(getCsound());
250 getThread()->SetProcessCallback(CsoundEngine::csThread, (void*)getUserData());
251 getThread()->Play();
252 return 0;
253 }
254
readScore(const QString & text)255 int CsoundHtmlWrapper::readScore(const QString &text) {
256 if (!m_csoundEngine) {
257 return -1;
258 }
259 if (isPlaying()) {
260 return csoundReadScore(getCsound(), text.toLocal8Bit());
261 }
262 return -1;
263 }
264
reset()265 void CsoundHtmlWrapper::reset() {
266 if (!m_csoundEngine) {
267 return;
268 }
269 csoundReset(getCsound());
270 }
271
rewindScore()272 void CsoundHtmlWrapper::rewindScore() {
273 if (!m_csoundEngine) {
274 return;
275 }
276 csoundRewindScore(getCsound());
277 }
278
runUtility(const QString & command,int argc,char ** argv)279 int CsoundHtmlWrapper::runUtility(const QString &command, int argc, char **argv) {
280 if (!m_csoundEngine) {
281 return -1;
282 }
283 return csoundRunUtility(getCsound(), command.toLocal8Bit(), argc, argv); // probably does not work from JS due char **
284 }
285
scoreEvent(char type,const double * pFields,long numFields)286 int CsoundHtmlWrapper::scoreEvent(char type, const double *pFields, long numFields) {
287 if (!m_csoundEngine) {
288 return -1;
289 }
290 return csoundScoreEvent(getCsound(),type, pFields, numFields);
291 }
292
setControlChannel(const QString & name,double value)293 void CsoundHtmlWrapper::setControlChannel(const QString &name, double value) {
294 if (!m_csoundEngine) {
295 return;
296 }
297 csoundSetControlChannel(getCsound(),name.toLocal8Bit(), value);
298 }
299
setGlobalEnv(const QString & name,const QString & value)300 int CsoundHtmlWrapper::setGlobalEnv(const QString &name, const QString &value) {
301 if (!m_csoundEngine) {
302 return -1;
303 }
304 return csoundSetGlobalEnv(name.toLocal8Bit(), value.toLocal8Bit());
305 }
306
setInput(const QString & name)307 void CsoundHtmlWrapper::setInput(const QString &name){
308 if (!m_csoundEngine) {
309 return;
310 }
311 #if CS_APIVERSION>=4
312 csoundSetInput(getCsound(), name.toLocal8Bit());
313 #else
314 csoundSetInput(getCsound(), name.toLocal8Bit().data());
315 #endif
316 }
317
setMessageCallback(QObject * callback)318 void CsoundHtmlWrapper::setMessageCallback(QObject *callback){
319 qDebug();
320 callback->dumpObjectInfo();
321 }
322
setOption(const QString & name)323 int CsoundHtmlWrapper::setOption(const QString &name){
324 if (!m_csoundEngine) {
325 return -1;
326 }
327 #if CS_APIVERSION>=4
328 return csoundSetOption(getCsound(), name.toLocal8Bit());
329 #else
330 return csoundSetOption(getCsound(), name.toLocal8Bit().data());
331 #endif
332 }
333
setOutput(const QString & name,const QString & type,const QString & format)334 void CsoundHtmlWrapper::setOutput(const QString &name, const QString &type, const QString &format){
335 if (!m_csoundEngine) {
336 return;
337 }
338 #if CS_APIVERSION>=4
339 csoundSetOutput(getCsound(), name.toLocal8Bit(), type.toLocal8Bit(), format.toLocal8Bit());
340 #else
341 csoundSetOutput(getCsound(), name.toLocal8Bit().data(), type.toLocal8Bit().data(), format.toLocal8Bit().data());
342 #endif
343 }
344
setScoreOffsetSeconds(double value)345 void CsoundHtmlWrapper::setScoreOffsetSeconds(double value){
346 if (!m_csoundEngine) {
347 return;
348 }
349 csoundSetScoreOffsetSeconds(getCsound(), value);
350 }
351
setScorePending(bool value)352 void CsoundHtmlWrapper::setScorePending(bool value){
353 if (!m_csoundEngine) {
354 return;
355 }
356 csoundSetScorePending(getCsound(),(int) value);
357 }
358
setStringChannel(const QString & name,const QString & value)359 void CsoundHtmlWrapper::setStringChannel(const QString &name, const QString &value){
360 if (!m_csoundEngine) {
361 return;
362 }
363 csoundSetStringChannel(getCsound(), name.toLocal8Bit(), value.toLocal8Bit().data());
364 }
365
start()366 int CsoundHtmlWrapper::start(){
367 if (!m_csoundEngine) {
368 return -1;
369 }
370 return csoundStart(getCsound());
371 }
372
stop()373 void CsoundHtmlWrapper::stop(){
374 if (!m_csoundEngine) {
375 return;
376 }
377 csoundStop(getCsound());
378 }
379
tableGet(int table_number,int index)380 double CsoundHtmlWrapper::tableGet(int table_number, int index){
381 if (!m_csoundEngine) {
382 return -1;
383 }
384 return csoundTableGet(getCsound(), table_number, index);
385 }
386
tableLength(int table_number)387 int CsoundHtmlWrapper::tableLength(int table_number){
388 if (!m_csoundEngine) {
389 return -1;
390 }
391 return csoundTableLength(getCsound(), table_number);
392 }
393
tableSet(int table_number,int index,double value)394 void CsoundHtmlWrapper::tableSet(int table_number, int index, double value){
395 if (!m_csoundEngine) {
396 return;
397 }
398 csoundTableSet(getCsound(), table_number, index, value);
399 }
400
401
csoundMessageCallback_(CSOUND * csound,int attributes,const char * format,va_list args)402 void CsoundHtmlWrapper::csoundMessageCallback_(CSOUND *csound,
403 int attributes,
404 const char *format,
405 va_list args) {
406 return reinterpret_cast<CsoundHtmlWrapper *>(csoundGetHostData(csound))->csoundMessageCallback(attributes, format, args);
407 }
408
csoundMessageCallback(int attributes,const char * format,va_list args)409 void CsoundHtmlWrapper::csoundMessageCallback(int attributes,
410 const char *format,
411 va_list args)
412 {
413 (void) attributes;
414 #ifdef USE_QT_GT_54
415 QString message = QString::vasprintf(format, args);
416 #else
417 QString message;
418 message.sprintf(format, args); // NB! Should pass but not tested!
419 #endif
420 qDebug() << message;
421 // if (!console->isHidden()) { // otherwise crash on exit
422 // passMessages(message);
423 // }
424 for (int i = 0, n = message.length(); i < n; i++) {
425 auto c = message[i];
426 if (c == '\n') {
427 QString code = "console.log(\"" + csoundMessageBuffer + "\\n\");";
428 if (csoundHtmlView != nullptr) {
429 #ifdef USE_WEBKIT
430 csoundHtmlView->webView->page()->mainFrame()->evaluateJavaScript(code);
431 #else
432 csoundHtmlView->webView->page()->runJavaScript(code);
433 #endif
434
435 }
436 csoundMessageBuffer.clear();
437 } else {
438 csoundMessageBuffer.append(c);
439 }
440 }
441 }
442