Just Intonation  Version 1.3.1 (19)
Explore key-independent dynamically adapting tuning in just intonation
application.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2016-2017 Karolin Stange, Christoph Wick, and Haye Hinrichsen
3  *
4  * This file is part of JustIntonation.
5  *
6  * JustIntonation is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * JustIntonation is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with JustIntonation. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //=============================================================================
21 // Application Class
22 //=============================================================================
23 
24 #include "application.h"
25 
26 #include <QLibraryInfo>
27 #include <QDir>
28 #include <QFile>
29 #include <QStandardPaths>
30 #include <QResource>
31 #include <QQmlProperty>
32 #include <QDialogButtonBox>
33 #include <QVariant>
34 
35 #include "config.h"
36 
37 // TODO Global application pointer for debugging, can be removed later
39 
40 //-----------------------------------------------------------------------------
41 // Application Constructor
42 //-----------------------------------------------------------------------------
46 
47 Application::Application(QApplication &app)
48  : pApplication(&app)
49  , mStartupSound(INT_STARTUPSOUND)
50  , mStarted(false)
51  , mSettings()
52  , mLocale()
53  , mRestartRequest(false)
54 
55  , mDownloader(INT_SAMPLES_REPOSITORY)
56  , mFileHandler()
57  , mMidiPlayer()
58  , mMidi()
59  , mMidiMicrotonalConverter()
60  , mAudioOutput()
61  , mNumberOfExample(1)
62  , mInstrument()
63  , mSoundGenerator()
64  , mMidiHandler(mSoundGenerator,mAudioOutput)
65  , mTuner()
66  , mTuningLog()
67  , mKeyboard()
68  , mAvailableMidiDevices()
69  , mAvailableMidiOutputDevices()
70  , mCurrentMidiDevice("")
71  , mMidiAutomaticRecognition(true)
72  , mMidiPlayerWasPlaying(false)
73  , mSuspended(false)
74  , mLastEmittedPitchProgression(0)
75 {
76  setModuleName("Main");
77 
78  // this->setVerbosity(4); // Application
79  // mSoundGenerator.setVerbosity(4);
80  // mMidiHandler.setVerbosity(4);
81  // mMidiPlayer.setVerbosity(4);
82  // mTuner.setVerbosity(4);
83  // mKeyboard.setVerbosity(4);
84  // mDownloader.setVerbosity(4);
85  // mInstrument.setVerbosity(4);
86  // mMidi.setVerbosity(4);
87  // mMidiMicrotonalConverter.setVerbosity(4);
88  // mAudioOutput.setVerbosity(4);
89 }
90 
91 
92 //-----------------------------------------------------------------------------
93 // Initialization of the application
94 //-----------------------------------------------------------------------------
102 
103 void Application::init (QQmlApplicationEngine &engine)
104 {
106 
107  //======================= C++ INTERNAL CONNECTIONS ========================
108 
109  // Connect application status
110  connect(pApplication,&QApplication::applicationStateChanged,this,&Application::handleApplicationStates);
111 
112  // Downloading instruments from the server to local disk
113  connect(&mDownloader,SIGNAL(signalNewFileDownloaded(QString)),this,SLOT(newInstrumentDownloaded(QString)));
114  connect(&mDownloader,SIGNAL(signalAllFilesDownloaded()),this,SLOT(allInstrumentsDownloaded()));
115 
116  // Instrument loading from local disk into RAM
118  connect(&mInstrument,SIGNAL(signalLoadingFinished(bool)),this,SLOT(loadingFinished(bool)));
119  connect(mInstrument.getVoice(),SIGNAL(signalArtificialSoundGenerationComplete(bool)),this,SLOT(loadingFinished(bool)));
120 
121  // Connect Midi sources to synthesizer and tuner
128 
129  // Tuning log
133 
134  // Connect microtonal Midi converter
139  connect(&mMidi,&Midi::onStatusChanged,
141 
142  // Connect pedal signals with sound-generating system
146 
147  // Connect tuner output with the sound-generating system and microtonal converter
150 
151  // Audio
152  connect(&mAudioOutput,SIGNAL(onAudioDevicesAdded(QStringList)),this,SLOT(onAudioDevicesAdded(QStringList)));
153  connect(&mAudioOutput,SIGNAL(onAudioDevicesRemoved(QStringList)),this,SLOT(onAudioDevicesRemoved(QStringList)));
154  connect(&mAudioOutput,SIGNAL(onChangeOfAvailableAudioDevices(QStringList)),this,SLOT(onChangeOfAvailableAudioDevices(QStringList)));
157  connect(this,SIGNAL(connectAudioDevice(bool)),&mAudioOutput,SLOT(connectDevice(bool)));
158 
159  //================ CONNECTIONS BETWEEN C++ AND THE QML LAYER ==============
160 
161  if (engine.rootObjects().empty()) return;
162  QObject* pQml = engine.rootObjects().first();
163  if (not pQml) return;
164 
165  // Restart application
166  connect(pQml,SIGNAL(restartApplication()),this,SLOT(restartApplication()));
167 
168  // Connect language chooser and initialize shown language
169  connect(pQml,SIGNAL(changeLocale(QString)),this,SLOT(changeLocale(QString)));
170  connect(this,SIGNAL(setQmlLocale(QVariant)),pQml,SLOT(setQmlLocale(QVariant)));
171  emit setQmlLocale(mLocale);
172 
173  // Instrument selector
174  connect(this,SIGNAL(setQmlInstrumentNames(QVariant)),pQml,SLOT(setQmlInstrumentNames(QVariant)));
175  connect(this,SIGNAL(setQmlSelectedInstrument(QVariant)),pQml,SLOT(setQmlSelectedInstrument(QVariant)));
176  connect(pQml,SIGNAL(selectInstrument(int)),this,SLOT(loadInstrument(int)));
177 
178  // Progress bar
179  connect(&mInstrument,SIGNAL(showProgressBar(QVariant)),pQml,SLOT(showProgressBar(QVariant)));
180  connect(&mInstrument,SIGNAL(hideProgressBar()),pQml,SLOT(hideProgressBar()));
181  connect(mInstrument.getVoice(),SIGNAL(setProgressText(QVariant)),pQml,SLOT(setProgressText(QVariant)));
182  connect(mInstrument.getVoice(),SIGNAL(setProgress(QVariant)),pQml,SLOT(setProgress(QVariant)));
183  connect(pQml,SIGNAL(progressCancelButton()),this,SLOT(cancelLoading()));
184 
185  // Midi player
186  connect(&mMidiPlayer,SIGNAL(signalPlayingStatusChanged(QVariant)),pQml,SLOT(setPlayingStatus(QVariant)));
187  connect(pQml,SIGNAL(togglePlayPause()),&mMidiPlayer,SLOT(togglePlayPause()));
188  connect(pQml,SIGNAL(hearExample(int)),this,SLOT(hearExample(int)));
189  connect(this,SIGNAL(setSelectedExample(QVariant)),pQml,SLOT(setQmlSelectedExample(QVariant)));
190  connect(pQml,SIGNAL(rewind()),&mMidiPlayer,SLOT(rewind()));
191  connect(pQml,SIGNAL(progressChangedManually(double)),&mMidiPlayer,SLOT(setMidiProgress(double)));
192  connect(pQml,SIGNAL(setTempoFactor(double)),&mMidiPlayer,SLOT(setTempo(double)));
193  connect(pQml,SIGNAL(setRepeatMode(bool)),&mMidiPlayer,SLOT(setRepeatMode(bool)));
194  connect(pQml,SIGNAL(openFile(QString)),&mMidiPlayer,SLOT(loadUrl(QString)));
196  connect(&mMidiPlayer,SIGNAL(signalProgressInPercent(QVariant)),pQml,SLOT(setMidiProgress(QVariant)));
197  connect(&mMidiPlayer,SIGNAL(setDisplayedMidiFilename(QVariant)),pQml,SLOT(setDisplayedMidiFilename(QVariant)));
198 
199  // Temperament selection
200  connect(pQml,SIGNAL(signalTuningMode(int,int)),&mTuner,SLOT(setTuningMode(int,int)));
201  connect(pQml,SIGNAL(signalCentsChanged(int,double)),&mTuner,SLOT(setIntervalSize(int,double)));
202  connect(pQml,SIGNAL(signalWeightsChanged(int,double)),&mTuner,SLOT(setIntervalWeight(int,double)));
203  connect(&mTuner,SIGNAL(signalReadyForReceivingParameters()),pQml,SLOT(sendAllCentsAndWeights()));
204  connect(pQml,SIGNAL(signalLoadCustomTemperament()),&mFileHandler,SLOT(loadData()));
205  connect(pQml,SIGNAL(signalSaveCustomTemperament(QString,QString,QString)),&mFileHandler,SLOT(saveData(QString,QString,QString)));
206  connect(&mFileHandler,SIGNAL(loadedData(QVariant,QVariant,QVariant)),pQml,SLOT(loadCustomTemperament(QVariant,QVariant,QVariant)));
207 
208  // Tuning delay
209  connect (pQml,SIGNAL(setTuningDelay(double)),&mTuner,SLOT(setDelayParameter(double)));
210 
211  // Static tuning
212  connect(pQml,SIGNAL(setStaticTuning(bool,int)),&mTuner,SLOT(setStaticTuningMode(bool,int)));
213 
214  // Drift correction
215  connect (pQml,SIGNAL(setDriftCorrectionParameter(double)),&mTuner,SLOT(setPitchProgressionCompensationParameter(double)));
216  connect (pQml,SIGNAL(setMemoryLength(double)),&mTuner,SLOT(setMemoryLength(double)));
217  connect (pQml,SIGNAL(resetPitchProgression()),&mTuner,SLOT(resetPitchProgression()));
218 
219  // Tuning log
220  connect (&mTuningLog,SIGNAL(signalNewLogMessage(QVariant)),pQml,SLOT(appendLogfile(QVariant)));
221  connect (&mMidiPlayer,SIGNAL(signalPlayingStatusChanged(QVariant)),pQml,SLOT(clearLogFile(QVariant)));
222  connect (pQml,SIGNAL(activateLogFile(bool)),&mTuningLog,SLOT(activateLogFile(bool)));
223 
224  // Target frequency
225  connect (&mMidiHandler,SIGNAL(changeTargetFrequency(QVariant)),pQml,SLOT(changeTargetFrequency(QVariant)));
226  connect (pQml,SIGNAL(setFrequencyOfA4(double)),&mTuner,SLOT(setFrequencyOfA4(double)));
227 
228  // Circular gauge for pitch progression
229  connect (&mTuner,SIGNAL(signalAveragePitchDrift(double)),this,SLOT(emitAveragePitchProgression(double)));
230  connect (this,SIGNAL(signalCircularGauge(QVariant)),pQml,SLOT(setAveragePitchDeviation(QVariant)));
231  connect (&mTuner,SIGNAL(signalIntervalString(QVariant)),pQml,SLOT(setIntervalString(QVariant)));
232  connect (&mTuner,SIGNAL(signalTension(QVariant)),pQml,SLOT(setTension(QVariant)));
233 
234  // Downloading instruments from the internet
235  connect(pQml,SIGNAL(startDownload(bool)),this,SLOT(startDownload(bool)));
236  connect(&mDownloader,SIGNAL(signalDownloading(QVariant)),pQml,SLOT(showDownloader(QVariant)));
237  connect(&mDownloader,SIGNAL(signalProgress(QVariant,QVariant)),pQml,SLOT(setDownloaderProgress(QVariant,QVariant)));
238  connect(&mDownloader,SIGNAL(signalNoInternetConnection(QVariant)),pQml,SLOT(noInternetConnection(QVariant)));
239 
240  // Audio settings
241  connect(this,SIGNAL(setAudioDeviceName(QVariant)),pQml,SLOT(setAudioDeviceName(QVariant)));
242  connect(this,SIGNAL(setAudioDeviceList(QVariant,QVariant)),pQml,SLOT(setAudioDeviceList(QVariant,QVariant)));
243  connect(this,SIGNAL(setAudioSampleRates(QVariant,QVariant)),pQml,SLOT(setAudioSampleRates(QVariant,QVariant)));
244  connect(pQml,SIGNAL(selectAudioParameters(int,int,int,int)),this,SLOT(selectAudioParameters(int,int,int,int)));
245  connect(pQml,SIGNAL(resetAudioParameters()),this,SLOT(resetAudioParameters()));
246  connect(pQml,SIGNAL(playStartupSound()),this,SLOT(playStartupSound()));
247  connect(this,SIGNAL(setAudioBufferSizes(QVariant,QVariant)),pQml,SLOT(setBufferSizes(QVariant,QVariant)));
248 
249  // Touchscreen keyboard
250  connect(pQml,SIGNAL(sendTouchscreenKeyboardEvent(QVariant)),
251  &mKeyboard,SLOT(receiveTouchpadKeyboardEvent(QVariant)));
252  connect(pQml,SIGNAL(setToggleMode(bool)),
253  &mKeyboard,SLOT(setToggleMode(bool)));
254  connect(pQml,SIGNAL(clearTouchscreenKeyboard()),
255  &mKeyboard,SLOT(clear()));
256  connect(&mKeyboard,SIGNAL(highlightKey(QVariant,QVariant)),
257  pQml,SLOT(highlightKey(QVariant,QVariant)));
258 
259  // Initialization procedure
260  connect(this,SIGNAL(getSettingsFromQml()),pQml,SLOT(getSettingsFromQml()));
261 
262  // TODO Message for debugging on mobile devices (temporarily)
263  globalApplicationPointer = this;
264  connect(this,SIGNAL(sendMobileMessage(QVariant)),pQml,SLOT(getMobileErrorMessage(QVariant)));
265 
266  // Midi remapper
267  connect(pQml,SIGNAL(onMidiOutputChannelChanged(int)),&mMidiMicrotonalConverter,SLOT(setMidiOutputChannel(int)));
268 
269  // Open Midi file dialog
270  connect(pQml,SIGNAL(openFileOpenDialog(int,int)),&mFileHandler,SLOT(openMidiFileDialog(int,int)));
271 
272  //======================= MAIN INITIALIZATION =============================
273 
275 
276  mAudioOutput.init();
278 
279  int buffersize=mSettings.value("audiooutput/buffersize",INT_BUFFERSIZE).toInt();
280  int packetsize=mSettings.value("audiooutput/packetsize",INT_PACKETSIZE).toInt();
281 
282  emit setAudioBufferSizes (buffersize,packetsize);
283  mInstrument.init();
285  mSoundGenerator.setMaxPacketSize(packetsize);
287  mInstrument.init();
288  mMidiHandler.init();
289 
290  mTuner.init();
291  mMidi.init(pQml);
292  //mMidiInputOutput.init(pQml);
294  mKeyboard.init();
295  mMidiPlayer.init();
296 }
297 
298 
299 //-----------------------------------------------------------------------------
300 // Start the application
301 //-----------------------------------------------------------------------------
305 
307 {
308  if (mStarted) return;
309  mStarted = true;
311  mInstrument.start();
315 
316  mTuner.start();
318  mKeyboard.start();
319  mMidiPlayer.start();
320 
321  // Load Midi file
322  bool midiFileLoaded = false;
323  #if (!defined(Q_OS_IOS) && !defined(Q_OS_ANDROID))
324  if (pApplication->arguments().size()==2)
325  midiFileLoaded = loadMidiFile(QUrl(pApplication->arguments()[1]).path());
326  #endif
327  if (not midiFileLoaded) mMidiPlayer.loadFile(":/audio/example1.mid");
328 
330 }
331 
332 
333 //-----------------------------------------------------------------------------
334 // Stop the application
335 //-----------------------------------------------------------------------------
339 
341 {
342  if (not mStarted) return;
343  mStarted = false;
344 
345  mMidiPlayer.stop();
346  mKeyboard.stop();
348  mTuner.stop();
349 
350 
351  QThread::msleep(200); // Wait 200 msec for the device to detach
352  mMidiHandler.stop();
354  mInstrument.stop();
355  mAudioOutput.stop();
356  mDownloader.stop();
357 }
358 
359 
360 //-----------------------------------------------------------------------------
361 // Exit
362 //-----------------------------------------------------------------------------
366 
368 {
369  mMidiPlayer.exit();
370  mKeyboard.exit();
372  mTuner.exit();
373 
374  mMidiHandler.exit();
376  mInstrument.exit();
377  mAudioOutput.exit();
378 }
379 
380 
381 //-----------------------------------------------------------------------------
382 // Suspend
383 //-----------------------------------------------------------------------------
389 
391 {
392  if (mSuspended) return;
394  mKeyboard.suspend();
396  mTuner.suspend();
397 
398  //mAudioOutput.suspend();
399 // mInstrument.suspend();
400 // mSoundGenerator.suspend();
401 // mMidiHandler.suspend();
402 
403  mSuspended = true;
404 }
405 
406 
407 //-----------------------------------------------------------------------------
408 // Resume
409 //-----------------------------------------------------------------------------
413 
415 {
416  if (not mSuspended) return;
417 
418  //mAudioOutput.resume();
419 // mInstrument.resume();
420 // mSoundGenerator.resume();
421 // mMidiHandler.resume();
422  //mMidiInput.resume();
423  //mMidiOutput.resume();
424 
425  mTuner.resume();
427  mKeyboard.resume();
429 
430  mSuspended = false;
431 }
432 
433 
434 //-----------------------------------------------------------------------------
435 // Function executed when application state changes
436 //-----------------------------------------------------------------------------
441 
442 void Application::handleApplicationStates(Qt::ApplicationState state)
443 {
444 #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
445  LOGMESSAGE << "******** Application state changed to" << state;
446  if (state==Qt::ApplicationActive) resume();
447  else suspend();
448 #else
449  (void)state;
450 // if (state==Qt::ApplicationActive) resume();
451 // else suspend();
452 #endif
453 }
454 
455 
456 //-----------------------------------------------------------------------------
457 // Install existing translations
458 //-----------------------------------------------------------------------------
464 
466 {
467  mLocale = mSettings.value("app/locale","").toString();
468  QString locale = (mLocale.size()>=2 ? mLocale : QLocale::system().name());
469  if (locale.mid(0,2)=="en") return;
470  QString qtqm = "qt_"+locale;
471  QString appqm = QString(INT_APPLICATIONNAME_LOWERCASE) + "_" + locale;
472  if (not mQtTranslator.load(qtqm,QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
473  {LOGWARNING << "Could not load translations for" << qtqm;}
474  else if (not pApplication->installTranslator(&mQtTranslator))
475  {LOGWARNING << "Could not install translations for" << qtqm;}
476  if (not mAppTranslator.load(appqm,":/languages/translations"))
477  {LOGWARNING << "Could not load translations for" << appqm;}
478  else if (not pApplication->installTranslator(&mAppTranslator))
479  {LOGWARNING << "Could not install translations for" << appqm;}
480 }
481 
482 
483 //-----------------------------------------------------------------------------
484 // Restart the application
485 //-----------------------------------------------------------------------------
489 
491 {
492  LOGMESSAGE << "Restart the application";
493  mRestartRequest = true;
494  if (pApplication) pApplication->exit();
495 }
496 
497 
498 //-----------------------------------------------------------------------------
499 // Change language
500 //-----------------------------------------------------------------------------
508 
509 void Application::changeLocale (QString locale)
510 {
511  LOGMESSAGE << "Change locale to" << locale;
512  if (locale == mLocale) return;
513  mSettings.setValue("app/locale",locale);
515 }
516 
517 
518 //-----------------------------------------------------------------------------
519 // Start download
520 //-----------------------------------------------------------------------------
524 
525 void Application::startDownload (bool forced)
526 {
527  LOGMESSAGE << "Slot called from Qml: Start download, forced =" << forced;
528  mDownloader.stop();
529  mDownloader.start(forced);
530 }
531 
532 
533 //-----------------------------------------------------------------------------
534 // Hear an example
535 //-----------------------------------------------------------------------------
540 
541 void Application::hearExample(int number)
542 {
543  if (number > 0)
544  {
546  mNumberOfExample = number;
548  QString resource = ":/audio/example"
549  + QString::number(mNumberOfExample)+".mid";
550  LOGMESSAGE << "loading " << resource;
551  mMidiPlayer.loadFile(resource);
552  mMidiPlayer.play();
553  }
554  else if (mMidiPlayer.isPlaying())
555  {
556  mMidiPlayer.pause();
560  QString resource = ":/audio/example"
561  + QString::number(mNumberOfExample)+".mid";
562  LOGMESSAGE << "loading " << resource;
563  mMidiPlayer.loadFile(resource);
564  }
565  else mMidiPlayer.play();
566 }
567 
568 
569 //-----------------------------------------------------------------------------
570 // Emit the newly calculated average pitch
571 //-----------------------------------------------------------------------------
578 
579 void Application::emitAveragePitchProgression (double pitchProgression)
580 {
581  if (pitchProgression > -50 and pitchProgression < 50)
582  {
583  mLastEmittedPitchProgression = pitchProgression;
585  }
586 }
587 
588 
589 //-----------------------------------------------------------------------------
590 // Update the list of instruments in the Qml Combo box
591 //-----------------------------------------------------------------------------
596 
598 {
599  LOGMESSAGE << "Update shown instrument names";
600  QStringList instruments = mDownloader.getPathsOfDownloadedFiles();
601  LOGSTATUS << "The paths of the instrument files are:" << instruments;
602 
603  // Translate the corresponding InstrumentQml names
604  QStringList InstrumentQmlNames = instruments;
605  for (QString &name : InstrumentQmlNames)
606  {
607  if (name.contains("Piano")) name=tr("Grand Piano");
608  else if (name.contains("Organ")) name=tr("Organ");
609  else if (name.contains("Harpsichord")) name=tr("Harpsichord");
610  else name=tr("Unknown Instrument");
611  }
612  InstrumentQmlNames.prepend(tr("Artificial sound"));
613  InstrumentQmlNames.append(tr("External device"));
614  LOGSTATUS << "Corresponding instrument names names:" << InstrumentQmlNames;
615 
616  emit setQmlInstrumentNames (InstrumentQmlNames);
617  return InstrumentQmlNames;
618 }
619 
620 
621 //-----------------------------------------------------------------------------
622 // Set the content of the instrument selector
623 //-----------------------------------------------------------------------------
627 
629 {
630  int numberOfInstruments = updateShownInstrumentNames().size();
631  if (index==0) index = mSettings.value("controller/instrumentindex",0).toInt();
632  if (index >= numberOfInstruments) index = 0;
633  emit setQmlSelectedInstrument(index);
634  loadInstrument(index);
635 }
636 
637 
638 //-----------------------------------------------------------------------------
639 // Load an instrument
640 //-----------------------------------------------------------------------------
644 
645 void Application::loadInstrument (int selectedindex)
646 {
647  // Index structure:
648  // 0: Artificial sound
649  // 1: Instrument 0
650  // 2: Instrument 1
651  // 3: Instrument 2
652  // 4: External Midi
653 
654  LOGMESSAGE << "Signal from Qml: Selected instrument number" << selectedindex;
655  const QStringList filenames = mDownloader.getPathsOfDownloadedFiles();
656  const int indexExternalMidi = filenames.size()+1;
657  if (selectedindex > indexExternalMidi)
658  {
659  LOGWARNING << "Cannot load file with index" << selectedindex;
660  return;
661  }
662 
667  QThread::msleep(200); // Wait 200 msec for sound generator to shut down
668 
670 
671  if (selectedindex == 0)
672  {
673  LOGMESSAGE << "Constructing artificial sound";
674  emit startLoadingInstrument("");
675  }
676  else if (selectedindex == indexExternalMidi)
677  {
679  }
680  else
681  {
682  const QString filename = filenames[selectedindex-1];
683  LOGMESSAGE << "Loading file with index" << selectedindex;
684  LOGMESSAGE << "Loading file" << filename;
685  emit startLoadingInstrument(filename);
686  }
687  mSettings.setValue("controller/instrumentindex",selectedindex);
688 }
689 
690 
691 //-----------------------------------------------------------------------------
692 // Cancel the loading process
693 //-----------------------------------------------------------------------------
697 
699 {
700  if (mInstrument.isLoading())
701  {
702  LOGMESSAGE << "*** CANCEL LOADING INSTRUMENT ***";
704  }
705 }
706 
707 
708 //-----------------------------------------------------------------------------
709 // Loading finished
710 //-----------------------------------------------------------------------------
714 
715 void Application::loadingFinished (bool success)
716 {
717  LOGMESSAGE << "Receiving signal that loading was finished";
718  (void)success;
721 }
722 
723 
724 //-----------------------------------------------------------------------------
725 // New instrument downloaded
726 //-----------------------------------------------------------------------------
730 
731 void Application::newInstrumentDownloaded (QString localpath)
732 {
733  LOGMESSAGE << "Receive signal: New instrument downloaded:";
734  LOGMESSAGE << localpath;
735  int number = updateShownInstrumentNames().size();
736  // If this is the first instrument download it automatically (+2)
737  if (number==3)
738  {
739  LOGMESSAGE << "First instrument is now loaded automatically";
741  }
742 }
743 
744 
745 //-----------------------------------------------------------------------------
746 // All instruments downloaded
747 //-----------------------------------------------------------------------------
752 {
753  LOGMESSAGE << "Receive signal: Downloader shutdown, now update instruments";
755 }
756 
757 
758 //================================= AUDIO =====================================
759 
760 //-----------------------------------------------------------------------------
761 // Shorten very long device names
762 //-----------------------------------------------------------------------------
769 
770 QString Application::shorten (const QString &device, int truncation) const
771 {
772  QString dev = device;
773 
774  // Especially for Microsoft Windows:
775  // If a short name is given in parentheses isolate that first
776  int opening = dev.indexOf("(");
777  int closing = dev.indexOf(")");
778  if (opening>0 and closing>opening)
779  dev = device.mid(opening+1,closing-opening-1);
780 
781  // In any case truncate
782  if (dev.size() > truncation)
783  {
784  dev.remove(0,dev.size()-truncation);
785  int pos1 = dev.indexOf("_");
786  int pos2 = dev.indexOf("-");
787  if (pos1>=0 and pos1<truncation/4) dev.remove(0,pos1+1);
788  else if (pos2>=0 and pos2<truncation/4) dev.remove(0,pos2+1);
789  }
790  return dev;
791 }
792 
793 
794 //-----------------------------------------------------------------------------
795 // Private slot: Select audio device parameters
796 //-----------------------------------------------------------------------------
804 
805 void Application::selectAudioParameters (int devIndex, int srIndex,
806  int buffersize, int packetsize)
807 {
809 
810  devIndex--; // Compensate leading entry "[Choose]"
811  LOGSTATUS << "Select audio device: Selection index =" << devIndex;
812  QStringList deviceNames = mAudioOutput.getListOfDevices();
813  if (devIndex < deviceNames.size() and devIndex>=0)
814  {
815  parameters.deviceName = deviceNames[devIndex];
816  LOGMESSAGE << "Selected device: " << parameters.deviceName;
817  }
818 
819  LOGSTATUS << "Select sample rate: Selection index =" << srIndex;
820  QList<int> listOfSampleRates = parameters.supportedSampleRates;
821  if (srIndex >= 0 and srIndex < listOfSampleRates.size())
822  {
823  parameters.sampleRate = listOfSampleRates[srIndex];
824  LOGMESSAGE << "Selected sample rate: Rate =" << parameters.sampleRate;
825  }
826 
827  LOGMESSAGE << "Select buffer size:" << buffersize;
828  parameters.bufferSize = buffersize;
829  mSettings.setValue("audiooutput/buffersize",buffersize);
830 
831  LOGMESSAGE << "Select packet size:" << packetsize;
832  mSoundGenerator.setMaxPacketSize(packetsize);
833  mSettings.setValue("audiooutput/packetsize",packetsize);
834 
835  mAudioOutput.setWantedParameters(parameters);
836  emit connectAudioDevice(true);
837 }
838 
839 
840 //-----------------------------------------------------------------------------
841 // Private slot: New audio device added (test)
842 //-----------------------------------------------------------------------------
847 
848 void Application::onAudioDevicesAdded (QStringList list)
849 {
850  LOGMESSAGE << "New audio device added" << list;
851 }
852 
853 
854 //-----------------------------------------------------------------------------
855 // Private slot: An audio device has been removed (test)
856 //-----------------------------------------------------------------------------
861 
863 {
864  LOGMESSAGE << "Audio removed" << list;
865 
866 }
867 
868 
869 //-----------------------------------------------------------------------------
870 // Private slot: The list of availabel devices has changed (test)
871 //-----------------------------------------------------------------------------
876 
878 {
879  LOGMESSAGE << "List of audio devices changed:" << list;
880  for (auto &e : list) e = shorten(e);
881  list.prepend(tr("[Choose output device]"));
882  QStringList devices = mAudioOutput.getListOfDevices();
884  int deviceIndex = devices.indexOf(parameters.deviceName);
885  emit setAudioDeviceList (list,deviceIndex+1);
886 
887  QStringList model;
888  for (auto &e : parameters.supportedSampleRates) model << QString::number(e);
889  int index = parameters.supportedSampleRates.indexOf(parameters.sampleRate);
890  emit setAudioSampleRates(model,index);
891 }
892 
893 
894 //-----------------------------------------------------------------------------
895 // Slot: on current audio device parameters changed
896 //-----------------------------------------------------------------------------
900 
902 {
903  LOGMESSAGE << "List of audio parameters changed.";
905  LOGMESSAGE << "DEVICE =" << parameters.deviceName << " SR =" << parameters.sampleRate;
906  QStringList model;
907  for (auto &e : parameters.supportedSampleRates) model << QString::number(e);
908  int index = parameters.supportedSampleRates.indexOf(parameters.sampleRate);
909  emit setAudioSampleRates(model,index);
910 }
911 
912 
913 //-----------------------------------------------------------------------------
914 // Slot: on audio connection established
915 //-----------------------------------------------------------------------------
920 
922 {
923  LOGMESSAGE << "Audio connected = " << success;
925  QString dev = parameters.deviceName;
926  if (dev.size()>0 and success) dev = shorten(dev);
927  else dev = tr("No device connected");
928  emit setAudioDeviceName(dev);
929 }
930 
931 
932 //-----------------------------------------------------------------------------
933 // Load a Midi file
934 //-----------------------------------------------------------------------------
939 
940 bool Application::loadMidiFile (QString filename)
941 {
942  LOGMESSAGE << "Trying to load Midi file" << filename;
943  QFile midifile (filename);
944  if (midifile.exists())
945  {
946  mMidiPlayer.loadFile(filename,true);
947  return true;
948  }
949  else
950  {
951  LOGWARNING << "MIDI File" << filename << "does not exist";
952  return false;
953  }
954 }
955 
956 
957 //-----------------------------------------------------------------------------
958 // Debug: Show error message on mobile
959 //-----------------------------------------------------------------------------
965 
966 void Application::mobileMessage(QString msg)
967 {
968  emit sendMobileMessage(msg);
969  qDebug() << "MOBILE ERROR MESSAGE" << msg;
970 }
971 
972 
973 //-----------------------------------------------------------------------------
974 // Slot: Closed Midi feedback loop discovered
975 //-----------------------------------------------------------------------------
979 
981 {
983  LOGWARNING << "Received signal about a closed Midi feedback loop";
984  // TODO message
985 }
986 
987 
988 //-----------------------------------------------------------------------------
989 // Slot: Closed Midi feedback loop discovered
990 //-----------------------------------------------------------------------------
994 
996 {
998 }
999 
1000 
1001 //-----------------------------------------------------------------------------
1002 // Slot: Reset Audio Parameters
1003 //-----------------------------------------------------------------------------
1007 
1009 {
1010  int buffersize = INT_BUFFERSIZE;
1011  int packetsize = INT_PACKETSIZE;
1012 
1013  auto parameters = mAudioOutput.getActualDeviceParameters();
1014 
1015  LOGMESSAGE << "Reset buffer size:" << buffersize;
1016  parameters.bufferSize = buffersize;
1017  mSettings.setValue("audiooutput/buffersize",buffersize);
1018 
1019  LOGMESSAGE << "Reset packet size:" << packetsize;
1020  mSoundGenerator.setMaxPacketSize(packetsize);
1021  mSettings.setValue("audiooutput/packetsize",packetsize);
1022 
1023  mAudioOutput.setWantedParameters(parameters);
1024  emit connectAudioDevice(true);
1025  emit setAudioBufferSizes (buffersize,packetsize);
1026 }
1027 
1028 
1029 //-----------------------------------------------------------------------------
1030 // Slot: Play the startup sound
1031 //-----------------------------------------------------------------------------
1035 
1037 {
1038  if (pApplication->arguments().size()<2) mStartupSound.play(0.2);
1039 }
1040 
1041 //-----------------------------------------------------------------------------
1042 // Debug: Show error message on mobile
1043 //-----------------------------------------------------------------------------
1045 
1047 
1048 void mobileError(QString msg)
1049 {
1050  globalApplicationPointer->mobileMessage(QString::number(mobileErrorCounter++) + ": " + msg);
1051 }
1052 
1053 
1054 
1055 // TODO Importer workaround:
1056 #include "instrument/wave.h"
void stop()
Stop the application and its components.
QSettings mSettings
Definition: application.h:153
void setInstrumentSelector(int index=0)
Set the content of the instrument selector.
void suspend()
Suspend the application This function suspends the application and all modules. This is essential e...
bool mMidiPlayerWasPlaying
Definition: application.h:176
void playStartupSound()
Play startup sound.
void resume()
Resume from suspend mode.
Definition: midiplayer.cpp:290
void setAudioSampleRates(QVariant list, QVariant index)
virtual bool init() override
Init audio device.
Definition: audiooutput.cpp:54
MidiMicrotonal mMidiMicrotonalConverter
Definition: application.h:163
bool loadMidiFile(QString filename)
Load a Midi file.
bool start() override final
Public slot: Start the tuner, starting the tuner thread.
Definition: tuner.cpp:94
bool mSuspended
Definition: application.h:177
bool stop()
Stop the microtonal converter.
double mLastEmittedPitchProgression
Definition: application.h:178
void changeLocale(QString locale)
Slot: Change the language.
void receiveTuningCorrections(QMap< int, double > corrections)
Input slot: Receive tuning corrections from the tuner (<key,cent>)
void hearExample(int number)
Private slot: Hear a Midi example.
void signalSostenutoPedal(bool pressed)
void play()
Start or resume playing.
Definition: midiplayer.cpp:203
void setModuleName(const QString &name)
Specify the name of the class-specific module.
Definition: log.cpp:82
virtual void suspend()
Mark the thread as suspended.
Definition: threadbase.cpp:84
void stop()
Stop downloading.
Definition: downloader.cpp:237
void newInstrumentDownloaded(QString localpath)
Private slot: New instrument downloaded.
void setQmlSelectedInstrument(QVariant index)
virtual void init(Application &application)
Platform-dependent initialization.
Definition: platformtools.h:66
MidiHandler mMidiHandler
Definition: application.h:168
int mobileErrorCounter
void handleApplicationStates(Qt::ApplicationState state)
Function executed when application state changes (platform-dependent) Takes action if the state of th...
static PlatformTools & getSingleton()
Definition: platformtools.h:56
void startLoadingInstrument(QString name)
Voice * getVoice()
Definition: instrument.h:46
void receiveTuningCorrections(QMap< int, double > corrections)
#define LOGMESSAGE
Definition: log.h:43
bool exit()
Shutdown, no functionality.
#define INT_SAMPLES_REPOSITORY
Definition: config.h:45
QString deviceName
Name of the audio device.
void onAudioDevicesRemoved(QStringList list)
Private slot: An audio device has been removed (test)
void setAudioDeviceName(QVariant name)
#define INT_BUFFERSIZE
Definition: config.h:103
void start(bool forced)
Start the downloading process in the background.
Definition: downloader.cpp:121
void play(double volume)
Play startup sound.
bool init() override final
Initialize the Tuner.
Definition: tuner.cpp:68
void init(QQmlApplicationEngine &engine)
Initialization of the application.
void receiveTuningCorrections(const QMap< int, double > &corrections)
Public slot: Receive tuning corrections.
Definition: logfile.cpp:124
bool init(QObject *qml)
Initialize the Midi wrapper and connect it with Qml.
Definition: midi.cpp:76
bool isPlaying() const
Find out whether the player is playing.
Definition: midiplayer.cpp:263
void setQmlInstrumentNames(QVariant stringlist)
void start()
Start the application and its components.
void setQmlLocale(QVariant string)
void connectAudioDevice(bool active)
void sendMidiEvent(QMidiMessage event)
Output signal: This is the converted outgoing stream of Midi events.
Structure holding the parameters and status of an audio device.
void onInputOutputStatusChanged()
I/O configuration changed, cancel converter inhibition.
virtual void resume()
Resume from the suspend mode.
Definition: threadbase.cpp:99
void mobileError(QString msg)
void openMidiFile(QString fileName, bool autostart)
virtual bool stop() override
Stop audio device.
Application(QApplication &app)
Application constructor.
Definition: application.cpp:47
QString shorten(const QString &device, int truncation=30) const
Shorten very long device names.
bool start()
Start the microtonal converter.
virtual bool init()
Virtual initialization function (no functionality here)
Definition: threadbase.h:70
#define INT_PACKETSIZE
Definition: config.h:104
void loadFile(QString filename, bool autostart=false)
Load a midi file (*.mid) from disk.
Definition: midiplayer.cpp:88
Downloader mDownloader
Definition: application.h:158
void emitAveragePitchProgression(double pitchProgression)
Emit the newly calculated average pitch progression.
QApplication * pApplication
Definition: application.h:150
void onConnectionSuccessfullyEstablished(bool success)
Private slot: on audio connection established.
void signalSoftPedal(bool pressed)
void allInstrumentsDownloaded()
Private slot: All instrumenst downloaded.
void activate(bool active)
Activate or deactivate the module.
void suspend()
Suspend (stop playing, thread idle)
Definition: midiplayer.cpp:275
int sampleRate
Actual sample rate.
void setAudioGenerator(AudioGenerator &generator)
Select an AudioGenerator for output.
void automaticCyclicMorphing()
Function defined externally (Importer)
void setMaxPacketSize(int n)
void getSettingsFromQml()
const AudioParameters getActualDeviceParameters() const
Get the actual audio device parameters.
Definition: audiobase.cpp:55
Application * globalApplicationPointer
Definition: application.cpp:38
Tuner mTuner
Definition: application.h:169
void receiveMidiEvent(const QMidiMessage &event)
Definition: midihandler.cpp:56
QTranslator mQtTranslator
Definition: application.h:156
Sampler & getSampler()
void disableScreenSaver()
Definition: application.h:115
void setSelectedExample(QVariant number)
void pause()
Pause: Interrupt playing.
Definition: midiplayer.cpp:228
#define INT_APPLICATIONNAME_LOWERCASE
Definition: config.h:34
void loadInstrument(int selectedindex)
Private slot: Load an instrument.
TouchscreenKeyboard mKeyboard
Definition: application.h:171
void exit()
Exit from the application and all its components.
void cancelLoading()
Definition: instrument.h:50
void sendTouchpadMidiEvent(QMidiMessage event)
Signal: On keypress send the corresponding Midi event to a different module.
MidiPlayer mMidiPlayer
Definition: application.h:161
void onStatusChanged()
void sendMidiMessage(const QMidiMessage &event)
Send a Midi message to the output device.
Definition: midi.cpp:126
void signalTuningCorrections(QMap< int, double > corrections)
Signal sending the tuning results to the microtonal sound device in the form of a map keyindex -> cen...
virtual bool exit() override
Exit audio device.
void resetAudioParameters()
Reset audio parameters.
Instrument mInstrument
Definition: application.h:166
void onAudioDevicesAdded(QStringList list)
Private slot: New audio device added (test)
void cancelLoading()
Private slot: Cancel the loading process.
void receiveMidiEvent(QMidiMessage event)
Public slot: Receive Midi event (Main input of the tuner)
Definition: tuner.cpp:271
bool mRestartRequest
Definition: application.h:155
int bufferSize
Buffer size of the device if applicable.
SoundGenerator mSoundGenerator
Definition: application.h:167
void resume()
Resume from suspend mode.
FileHandler mFileHandler
Definition: application.h:159
void restartApplication()
Restart the application by force.
bool stop() override final
Stop the instrument thread.
Definition: instrument.cpp:54
void receiveMidiEvent(QMidiMessage event)
Public slot: Receive MIDI event.
Definition: logfile.cpp:92
#define LOGSTATUS
Definition: log.h:42
void setSustainPedal(bool pressed)
StartupSound mStartupSound
Definition: application.h:151
bool init()
Initialization, no functionality.
void startDownload(bool forced=false)
Private slot: Start download.
void resume()
resume
void loadInstrument(QString path)
Load or generate an instrument (voice)
Definition: instrument.cpp:72
AudioOutput mAudioOutput
Definition: application.h:164
virtual bool exit()
Virtual exit function (no functionality here)
Definition: threadbase.h:71
void loadingFinished(bool success)
Private slot: Loading finished.
void selectAudioParameters(int devIndex, int srIndex, int buffersize, int packetsize)
Private slot: Select audio parameters.
#define INT_NUMBER_OF_EXAMPLES
Definition: config.h:57
void setAudioDeviceList(QVariant list, QVariant index)
void setSoftPedal(bool pressed)
void suspend()
Suspend the microtonal converter.
QString mLocale
Definition: application.h:154
virtual bool start()
Start the thread.
Definition: threadbase.cpp:64
void sendMobileMessage(QVariant string)
bool isLoading()
Definition: instrument.h:43
void installTranslations()
Install existing translations.
void suspend() override final
Mark the thread as suspended.
void togglePlayPause()
Toggle between play and pause.
Definition: midiplayer.cpp:173
QStringList updateShownInstrumentNames()
Update the list of instruments in the Qml Combo box.
void onChangeOfAvailableAudioDevices(QStringList list)
Private slot: The list of availabel devices has changed (test)
Main application.
Definition: application.h:60
int mNumberOfExample
Definition: application.h:165
QList< int > supportedSampleRates
List of supported sample rates.
void reInitializeConvertedMidiStream()
Slot: Re-initialize the output stream.
QTranslator mAppTranslator
Definition: application.h:157
void receiveMidiEvent(const QMidiMessage event)
Input slot: Here the module receives the stream of incoming Midi events.
void setAudioBufferSizes(QVariant buffer, QVariant packet)
void onCurrentDeviceParametersChanged()
Private slot: on current audio device parameters changed.
void mobileMessage(QString msg)
Show error message on mobile phone while it is connected to a keyboard.
bool stop()
Stop the player.
Definition: midiplayer.cpp:68
void init(Application *application, Voice *voice)
Initialize the SoundGenerator.
void signalMidiEvent(QMidiMessage event)
void signalCircularGauge(QVariant progression)
virtual bool stop()
Stop the thread.
Definition: threadbase.cpp:152
QStringList getPathsOfDownloadedFiles()
Get a list of paths of all downloaded files.
Definition: downloader.cpp:319
void signalSustainPedal(bool pressed)
void setWantedParameters(const AudioParameters &parameters)
Set the wanted audio device parameters.
Definition: audiobase.cpp:100
LogFile mTuningLog
Definition: application.h:170
void setDefaultBufferSize(int n)
Definition: audiooutput.h:64
QStringList getListOfDevices() const
Get the current list of devices from the last update.
Definition: audiobase.h:70
virtual bool start() override
Start audio device.
Definition: audiooutput.cpp:69
void receivedMidiMessage(const QMidiMessage &event)
void onClosedMidiLoopDetected()
Slot: Closed Midi feedback loop discovered, inhibit converter.
#define LOGWARNING
Definition: log.h:44
void setSostenutoPedal(bool pressed)
#define INT_STARTUPSOUND
Definition: config.h:52