Just Intonation  Version 1.3.0 (18)
Explore scale-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  , mFileOpenDialog()
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 
115  // Instrument loading from local disk into RAM
117  connect(&mInstrument,SIGNAL(signalLoadingFinished(bool)),this,SLOT(loadingFinished(bool)));
118  connect(mInstrument.getVoice(),SIGNAL(signalArtificialSoundGenerationComplete(bool)),this,SLOT(loadingFinished(bool)));
119 
120  // Connect Midi sources to synthesizer and tuner
127 
128  // Tuning log
132 
133  // Connect microtonal Midi converter
138  connect(&mMidi,&Midi::onStatusChanged,
140 
141  // Connect pedal signals with sound-generating system
145 
146  // Connect tuner output with the sound-generating system and microtonal converter
149 
150  // Audio
151  connect(&mAudioOutput,SIGNAL(onAudioDevicesAdded(QStringList)),this,SLOT(onAudioDevicesAdded(QStringList)));
152  connect(&mAudioOutput,SIGNAL(onAudioDevicesRemoved(QStringList)),this,SLOT(onAudioDevicesRemoved(QStringList)));
153  connect(&mAudioOutput,SIGNAL(onChangeOfAvailableAudioDevices(QStringList)),this,SLOT(onChangeOfAvailableAudioDevices(QStringList)));
156  connect(this,SIGNAL(connectAudioDevice(bool)),&mAudioOutput,SLOT(connectDevice(bool)));
157 
158  //================ CONNECTIONS BETWEEN C++ AND THE QML LAYER ==============
159 
160  if (engine.rootObjects().empty()) return;
161  QObject* pQml = engine.rootObjects().first();
162  if (not pQml) return;
163 
164  // Restart application
165  connect(pQml,SIGNAL(restartApplication()),this,SLOT(restartApplication()));
166 
167  // Connect language chooser and initialize shown language
168  connect(pQml,SIGNAL(changeLocale(QString)),this,SLOT(changeLocale(QString)));
169  connect(this,SIGNAL(setQmlLocale(QVariant)),pQml,SLOT(setQmlLocale(QVariant)));
170  emit setQmlLocale(mLocale);
171 
172  // Instrument selector
173  connect(this,SIGNAL(setQmlInstrumentNames(QVariant)),pQml,SLOT(setQmlInstrumentNames(QVariant)));
174  connect(this,SIGNAL(setQmlSelectedInstrument(QVariant)),pQml,SLOT(setQmlSelectedInstrument(QVariant)));
175  connect(pQml,SIGNAL(selectInstrument(int)),this,SLOT(loadInstrument(int)));
176 
177  // Progress bar
178  connect(&mInstrument,SIGNAL(showProgressBar(QVariant)),pQml,SLOT(showProgressBar(QVariant)));
179  connect(&mInstrument,SIGNAL(hideProgressBar()),pQml,SLOT(hideProgressBar()));
180  connect(mInstrument.getVoice(),SIGNAL(setProgressText(QVariant)),pQml,SLOT(setProgressText(QVariant)));
181  connect(mInstrument.getVoice(),SIGNAL(setProgress(QVariant)),pQml,SLOT(setProgress(QVariant)));
182  connect(pQml,SIGNAL(progressCancelButton()),this,SLOT(cancelLoading()));
183 
184  // Midi player
185  connect(&mMidiPlayer,SIGNAL(signalPlayingStatusChanged(QVariant)),pQml,SLOT(setPlayingStatus(QVariant)));
186  connect(pQml,SIGNAL(togglePlayPause()),&mMidiPlayer,SLOT(togglePlayPause()));
187  connect(pQml,SIGNAL(hearExample(int)),this,SLOT(hearExample(int)));
188  connect(this,SIGNAL(setSelectedExample(QVariant)),pQml,SLOT(setQmlSelectedExample(QVariant)));
189  connect(pQml,SIGNAL(rewind()),&mMidiPlayer,SLOT(rewind()));
190  connect(pQml,SIGNAL(progressChangedManually(double)),&mMidiPlayer,SLOT(setMidiProgress(double)));
191  connect(pQml,SIGNAL(setTempoFactor(double)),&mMidiPlayer,SLOT(setTempo(double)));
192  connect(pQml,SIGNAL(setRepeatMode(bool)),&mMidiPlayer,SLOT(setRepeatMode(bool)));
193  connect(pQml,SIGNAL(openFile(QString)),&mMidiPlayer,SLOT(loadUrl(QString)));
195  connect(&mMidiPlayer,SIGNAL(signalProgressInPercent(QVariant)),pQml,SLOT(setMidiProgress(QVariant)));
196  connect(&mMidiPlayer,SIGNAL(setDisplayedMidiFilename(QVariant)),pQml,SLOT(setDisplayedMidiFilename(QVariant)));
197 
198  // Temperament selection
199  connect(pQml,SIGNAL(signalTuningMode(int,int)),&mTuner,SLOT(setTuningMode(int,int)));
200  connect(pQml,SIGNAL(signalCentsChanged(int,double)),&mTuner,SLOT(setIntervalSize(int,double)));
201  connect(pQml,SIGNAL(signalWeightsChanged(int,double)),&mTuner,SLOT(setIntervalWeight(int,double)));
202  connect(&mTuner,SIGNAL(signalReadyForReceivingParameters()),pQml,SLOT(sendAllCentsAndWeights()));
203 
204  // Tuning delay
205  connect (pQml,SIGNAL(setTuningDelay(double)),&mTuner,SLOT(setDelayParameter(double)));
206 
207  // Static tuning
208  connect(pQml,SIGNAL(setStaticTuning(bool,int)),&mTuner,SLOT(setStaticTuningMode(bool,int)));
209 
210  // Drift correction
211  connect (pQml,SIGNAL(setDriftCorrectionParameter(double)),&mTuner,SLOT(setPitchProgressionCompensationParameter(double)));
212  connect (pQml,SIGNAL(setMemoryLength(double)),&mTuner,SLOT(setMemoryLength(double)));
213  connect (pQml,SIGNAL(resetPitchProgression()),&mTuner,SLOT(resetPitchProgression()));
214 
215  // Tuning log
216  connect (&mTuningLog,SIGNAL(signalNewLogMessage(QVariant)),pQml,SLOT(appendLogfile(QVariant)));
217  connect (&mMidiPlayer,SIGNAL(signalPlayingStatusChanged(QVariant)),pQml,SLOT(clearLogFile(QVariant)));
218  connect (pQml,SIGNAL(activateLogFile(bool)),&mTuningLog,SLOT(activateLogFile(bool)));
219 
220  // Target frequency
221  connect (&mMidiHandler,SIGNAL(changeTargetFrequency(QVariant)),pQml,SLOT(changeTargetFrequency(QVariant)));
222  connect (pQml,SIGNAL(setFrequencyOfA4(double)),&mTuner,SLOT(setFrequencyOfA4(double)));
223 
224  // Circular gauge for pitch progression
225  connect (&mTuner,SIGNAL(signalAveragePitchProgression(double)),this,SLOT(emitAveragePitchProgression(double)));
226  connect (this,SIGNAL(signalCircularGauge(QVariant)),pQml,SLOT(setAveragePitchDeviation(QVariant)));
227  connect (&mTuner,SIGNAL(signalIntervalString(QVariant)),pQml,SLOT(setIntervalString(QVariant)));
228  connect (&mTuner,SIGNAL(signalTension(QVariant)),pQml,SLOT(setTension(QVariant)));
229 
230  // Downloading instruments from the internet
231  connect(pQml,SIGNAL(startDownload(bool)),this,SLOT(startDownload(bool)));
232  connect(&mDownloader,SIGNAL(signalDownloading(QVariant)),pQml,SLOT(showDownloader(QVariant)));
233  connect(&mDownloader,SIGNAL(signalProgress(QVariant,QVariant)),pQml,SLOT(setDownloaderProgress(QVariant,QVariant)));
234  connect(&mDownloader,SIGNAL(signalNoInternetConnection(QVariant)),pQml,SLOT(noInternetConnection(QVariant)));
235 
236  // Audio settings
237  connect(this,SIGNAL(setAudioDeviceName(QVariant)),pQml,SLOT(setAudioDeviceName(QVariant)));
238  connect(this,SIGNAL(setAudioDeviceList(QVariant,QVariant)),pQml,SLOT(setAudioDeviceList(QVariant,QVariant)));
239  connect(this,SIGNAL(setAudioSampleRates(QVariant,QVariant)),pQml,SLOT(setAudioSampleRates(QVariant,QVariant)));
240  connect(pQml,SIGNAL(selectAudioParameters(int,int,int,int)),this,SLOT(selectAudioParameters(int,int,int,int)));
241  connect(pQml,SIGNAL(resetAudioParameters()),this,SLOT(resetAudioParameters()));
242  connect(this,SIGNAL(setAudioBufferSizes(QVariant,QVariant)),pQml,SLOT(setBufferSizes(QVariant,QVariant)));
243 
244  // Touchscreen keyboard
245  connect(pQml,SIGNAL(sendTouchscreenKeyboardEvent(QVariant)),
246  &mKeyboard,SLOT(receiveTouchpadKeyboardEvent(QVariant)));
247  connect(pQml,SIGNAL(setToggleMode(bool)),
248  &mKeyboard,SLOT(setToggleMode(bool)));
249  connect(pQml,SIGNAL(clearTouchscreenKeyboard()),
250  &mKeyboard,SLOT(clear()));
251  connect(&mKeyboard,SIGNAL(highlightKey(QVariant,QVariant)),
252  pQml,SLOT(highlightKey(QVariant,QVariant)));
253 
254  // Initialization procedure
255  connect(this,SIGNAL(getSettingsFromQml()),pQml,SLOT(getSettingsFromQml()));
256 
257  // TODO Message for debugging on mobile devices (temporarily)
258  globalApplicationPointer = this;
259  connect(this,SIGNAL(sendMobileMessage(QVariant)),pQml,SLOT(getMobileErrorMessage(QVariant)));
260 
261  // Midi remapper
262  connect(pQml,SIGNAL(onMidiOutputChannelChanged(int)),&mMidiMicrotonalConverter,SLOT(setMidiOutputChannel(int)));
263 
264  // Open file dialog
265  connect(pQml,SIGNAL(openFileOpenDialog(int,int)),&mFileOpenDialog,SLOT(open(int,int)));
266 
267  //======================= MAIN INITIALIZATION =============================
268 
270 
271  mAudioOutput.init();
272  mAudioOutput.setDefaultBufferSize(INT_BUFFERSIZE);
273 
274  int buffersize=mSettings.value("audiooutput/buffersize",INT_BUFFERSIZE).toInt();
275  int packetsize=mSettings.value("audiooutput/packetsize",INT_PACKETSIZE).toInt();
276 
277  emit setAudioBufferSizes (buffersize,packetsize);
278  mInstrument.init();
280  mSoundGenerator.setMaxPacketSize(packetsize);
282  mInstrument.init();
283  mMidiHandler.init();
284 
285  mTuner.init();
286  mMidi.init(pQml);
287  //mMidiInputOutput.init(pQml);
289  mKeyboard.init();
290  mMidiPlayer.init();
291 
292  if (pApplication->arguments().size()<2) mStartupSound.play();
293 }
294 
295 
296 //-----------------------------------------------------------------------------
297 // Start the application
298 //-----------------------------------------------------------------------------
302 
304 {
305  if (mStarted) return;
306  mStarted = true;
308  mInstrument.start();
312 
313  mTuner.start();
315  mKeyboard.start();
316  mMidiPlayer.start();
317 
318  // Load Midi file
319  bool midiFileLoaded = false;
320  #if (!defined(Q_OS_IOS) && !defined(Q_OS_ANDROID))
321  if (pApplication->arguments().size()==2)
322  midiFileLoaded = loadMidiFile(QUrl(pApplication->arguments()[1]).path());
323  #endif
324  if (not midiFileLoaded) mMidiPlayer.loadFile(":/audio/example1.mid");
325 
327 }
328 
329 
330 //-----------------------------------------------------------------------------
331 // Stop the application
332 //-----------------------------------------------------------------------------
336 
338 {
339  if (not mStarted) return;
340  mStarted = false;
341 
342  mMidiPlayer.stop();
343  mKeyboard.stop();
345  mTuner.stop();
346 
347 
348  QThread::msleep(200); // Wait 200 msec for the device to detach
349  mMidiHandler.stop();
351  mInstrument.stop();
352  mAudioOutput.stop();
353  mDownloader.stop();
354 }
355 
356 
357 //-----------------------------------------------------------------------------
358 // Exit
359 //-----------------------------------------------------------------------------
363 
365 {
366  mMidiPlayer.exit();
367  mKeyboard.exit();
369  mTuner.exit();
370 
371  mMidiHandler.exit();
373  mInstrument.exit();
374  mAudioOutput.exit();
375 }
376 
377 
378 //-----------------------------------------------------------------------------
379 // Suspend
380 //-----------------------------------------------------------------------------
386 
388 {
389  if (mSuspended) return;
391  mKeyboard.suspend();
393  mTuner.suspend();
394 
395  //mAudioOutput.suspend();
396 // mInstrument.suspend();
397 // mSoundGenerator.suspend();
398 // mMidiHandler.suspend();
399 
400  mSuspended = true;
401 }
402 
403 
404 //-----------------------------------------------------------------------------
405 // Resume
406 //-----------------------------------------------------------------------------
410 
412 {
413  if (not mSuspended) return;
414 
415  //mAudioOutput.resume();
416 // mInstrument.resume();
417 // mSoundGenerator.resume();
418 // mMidiHandler.resume();
419  //mMidiInput.resume();
420  //mMidiOutput.resume();
421 
422  mTuner.resume();
424  mKeyboard.resume();
426 
427  mSuspended = false;
428 }
429 
430 
431 //-----------------------------------------------------------------------------
432 // Function executed when application state changes
433 //-----------------------------------------------------------------------------
438 
439 void Application::handleApplicationStates(Qt::ApplicationState state)
440 {
441 #if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
442  LOGMESSAGE << "******** Application state changed to" << state;
443  if (state==Qt::ApplicationActive) resume();
444  else suspend();
445 #else
446  (void)state;
447 // if (state==Qt::ApplicationActive) resume();
448 // else suspend();
449 #endif
450 }
451 
452 
453 //-----------------------------------------------------------------------------
454 // Install existing translations
455 //-----------------------------------------------------------------------------
461 
463 {
464  mLocale = mSettings.value("app/locale","").toString();
465  QString locale = (mLocale.size()>=2 ? mLocale : QLocale::system().name());
466  if (locale.mid(0,2)=="en") return;
467  QString qtqm = "qt_"+locale;
468  QString appqm = QString(INT_APPLICATIONNAME_LOWERCASE) + "_" + locale;
469  if (not mQtTranslator.load(qtqm,QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
470  LOGWARNING << "Could not load translations for" << qtqm;
471  if (not mAppTranslator.load(appqm,":/languages/translations"))
472  LOGWARNING << "Could not load translations for" << appqm;
473  if (not pApplication->installTranslator(&mQtTranslator))
474  LOGWARNING << "Could not install translations for" << qtqm;
475  if (not pApplication->installTranslator(&mAppTranslator))
476  LOGWARNING << "Could not install translations for" << appqm;
477 }
478 
479 
480 //-----------------------------------------------------------------------------
481 // Restart the application
482 //-----------------------------------------------------------------------------
486 
488 {
489  LOGMESSAGE << "Restart the application";
490  mRestartRequest = true;
491  if (pApplication) pApplication->exit();
492 }
493 
494 
495 //-----------------------------------------------------------------------------
496 // Change language
497 //-----------------------------------------------------------------------------
505 
506 void Application::changeLocale (QString locale)
507 {
508  LOGMESSAGE << "Change locale to" << locale;
509  if (locale == mLocale) return;
510  mSettings.setValue("app/locale",locale);
512 }
513 
514 
515 //-----------------------------------------------------------------------------
516 // Start download
517 //-----------------------------------------------------------------------------
521 
522 void Application::startDownload (bool forced)
523 {
524  LOGMESSAGE << "Slot called from Qml: Start download, forced =" << forced;
525  mDownloader.stop();
526  mDownloader.start(forced);
527 }
528 
529 
530 //-----------------------------------------------------------------------------
531 // Hear an example
532 //-----------------------------------------------------------------------------
537 
538 void Application::hearExample(int number)
539 {
540  if (number > 0)
541  {
543  mNumberOfExample = number;
545  QString resource = ":/audio/example"
546  + QString::number(mNumberOfExample)+".mid";
547  LOGMESSAGE << "loading " << resource;
548  mMidiPlayer.loadFile(resource);
549  mMidiPlayer.play();
550  }
551  else if (mMidiPlayer.isPlaying())
552  {
553  mMidiPlayer.pause();
557  QString resource = ":/audio/example"
558  + QString::number(mNumberOfExample)+".mid";
559  LOGMESSAGE << "loading " << resource;
560  mMidiPlayer.loadFile(resource);
561  }
562  else mMidiPlayer.play();
563 }
564 
565 
566 //-----------------------------------------------------------------------------
567 // Emit the newly calculated average pitch
568 //-----------------------------------------------------------------------------
575 
576 void Application::emitAveragePitchProgression (double pitchProgression)
577 {
578  if (pitchProgression > -50 and pitchProgression < 50)
579  {
580  mLastEmittedPitchProgression = pitchProgression;
582  }
583 }
584 
585 
586 //-----------------------------------------------------------------------------
587 // Update the list of instruments in the Qml Combo box
588 //-----------------------------------------------------------------------------
593 
595 {
596  LOGMESSAGE << "Update shown instrument names";
597  QStringList instruments = mDownloader.getPathsOfDownloadedFiles();
598  LOGSTATUS << "The paths of the instrument files are:" << instruments;
599 
600  // Translate the corresponding InstrumentQml names
601  QStringList InstrumentQmlNames = instruments;
602  for (QString &name : InstrumentQmlNames)
603  {
604  if (name.contains("Piano")) name=tr("Grand Piano");
605  else if (name.contains("Organ")) name=tr("Organ");
606  else if (name.contains("Harpsichord")) name=tr("Harpsichord");
607  else name=tr("Unknown Instrument");
608  }
609  InstrumentQmlNames.prepend(tr("Artificial sound"));
610  InstrumentQmlNames.append(tr("External device"));
611  LOGSTATUS << "Corresponding instrument names names:" << InstrumentQmlNames;
612 
613  emit setQmlInstrumentNames (InstrumentQmlNames);
614  return InstrumentQmlNames;
615 }
616 
617 
618 //-----------------------------------------------------------------------------
619 // Set the content of the instrument selector
620 //-----------------------------------------------------------------------------
624 
626 {
627  int numberOfInstruments = updateShownInstrumentNames().size();
628  if (index==0) index = mSettings.value("controller/instrumentindex",0).toInt();
629  if (index >= numberOfInstruments) index = 0;
630  emit setQmlSelectedInstrument(index);
631  loadInstrument(index);
632 }
633 
634 
635 //-----------------------------------------------------------------------------
636 // Load an instrument
637 //-----------------------------------------------------------------------------
641 
642 void Application::loadInstrument (int selectedindex)
643 {
644  // Index structure:
645  // 0: Artificial sound
646  // 1: Instrument 0
647  // 2: Instrument 1
648  // 3: Instrument 2
649  // 4: External Midi
650 
651  LOGMESSAGE << "Signal from Qml: Selected instrument number" << selectedindex;
652  const QStringList filenames = mDownloader.getPathsOfDownloadedFiles();
653  const int indexExternalMidi = filenames.size()+1;
654  if (selectedindex > indexExternalMidi)
655  {
656  LOGWARNING << "Cannot load file with index" << selectedindex;
657  return;
658  }
659 
664  QThread::msleep(200); // Wait 200 msec for sound generator to shut down
665 
667 
668  if (selectedindex == 0)
669  {
670  LOGMESSAGE << "Constructing artificial sound";
671  emit startLoadingInstrument("");
672  }
673  else if (selectedindex == indexExternalMidi)
674  {
676  }
677  else
678  {
679  const QString filename = filenames[selectedindex-1];
680  LOGMESSAGE << "Loading file with index" << selectedindex;
681  LOGMESSAGE << "Loading file" << filename;
682  emit startLoadingInstrument(filename);
683  }
684  mSettings.setValue("controller/instrumentindex",selectedindex);
685 }
686 
687 
688 //-----------------------------------------------------------------------------
689 // Cancel the loading process
690 //-----------------------------------------------------------------------------
694 
696 {
697  if (mInstrument.isLoading())
698  {
699  LOGMESSAGE << "*** CANCEL LOADING INSTRUMENT ***";
701  }
702 }
703 
704 
705 //-----------------------------------------------------------------------------
706 // Loading finished
707 //-----------------------------------------------------------------------------
711 
712 void Application::loadingFinished (bool success)
713 {
714  LOGMESSAGE << "Receiving signal that loading was finished";
715  (void)success;
718 }
719 
720 
721 //-----------------------------------------------------------------------------
722 // New instrument downloaded
723 //-----------------------------------------------------------------------------
727 
728 void Application::newInstrumentDownloaded (QString localpath)
729 {
730  LOGMESSAGE << "Receive signal: New instrument downloaded:";
731  LOGMESSAGE << localpath;
732  int number = updateShownInstrumentNames().size();
733  // If this is the first instrument download it automatically (+2)
734  if (number==3)
735  {
736  LOGMESSAGE << "First instrument is now loaded automatically";
738  }
739 }
740 
741 //================================= AUDIO =====================================
742 
743 //-----------------------------------------------------------------------------
744 // Shorten very long device names
745 //-----------------------------------------------------------------------------
752 
753 QString Application::shorten (const QString &device, int truncation) const
754 {
755  QString dev = device;
756 
757  // Especially for Microsoft Windows:
758  // If a short name is given in parentheses isolate that first
759  int opening = dev.indexOf("(");
760  int closing = dev.indexOf(")");
761  if (opening>0 and closing>opening)
762  dev = device.mid(opening+1,closing-opening-1);
763 
764  // In any case truncate
765  if (dev.size() > truncation)
766  {
767  dev.remove(0,dev.size()-truncation);
768  int pos1 = dev.indexOf("_");
769  int pos2 = dev.indexOf("-");
770  if (pos1>=0 and pos1<truncation/4) dev.remove(0,pos1+1);
771  else if (pos2>=0 and pos2<truncation/4) dev.remove(0,pos2+1);
772  }
773  return dev;
774 }
775 
776 
777 //-----------------------------------------------------------------------------
778 // Private slot: Select audio device parameters
779 //-----------------------------------------------------------------------------
787 
788 void Application::selectAudioParameters (int devIndex, int srIndex,
789  int buffersize, int packetsize)
790 {
792 
793  devIndex--; // Compensate leading entry "[Choose]"
794  LOGSTATUS << "Select audio device: Selection index =" << devIndex;
795  QStringList deviceNames = mAudioOutput.getListOfDevices();
796  if (devIndex < deviceNames.size() and devIndex>=0)
797  {
798  parameters.deviceName = deviceNames[devIndex];
799  LOGMESSAGE << "Selected device: " << parameters.deviceName;
800  }
801 
802  LOGSTATUS << "Select sample rate: Selection index =" << srIndex;
803  QList<int> listOfSampleRates = parameters.supportedSampleRates;
804  if (srIndex >= 0 and srIndex < listOfSampleRates.size())
805  {
806  parameters.sampleRate = listOfSampleRates[srIndex];
807  LOGMESSAGE << "Selected sample rate: Rate =" << parameters.sampleRate;
808  }
809 
810  LOGMESSAGE << "Select buffer size:" << buffersize;
811  parameters.bufferSize = buffersize;
812  mSettings.setValue("audiooutput/buffersize",buffersize);
813 
814  LOGMESSAGE << "Select packet size:" << packetsize;
815  mSoundGenerator.setMaxPacketSize(packetsize);
816  mSettings.setValue("audiooutput/packetsize",packetsize);
817 
818  mAudioOutput.setWantedParameters(parameters);
819  emit connectAudioDevice(true);
820 }
821 
822 
823 //-----------------------------------------------------------------------------
824 // Private slot: New audio device added (test)
825 //-----------------------------------------------------------------------------
830 
831 void Application::onAudioDevicesAdded (QStringList list)
832 {
833  LOGMESSAGE << "New audio device added" << list;
834 }
835 
836 
837 //-----------------------------------------------------------------------------
838 // Private slot: An audio device has been removed (test)
839 //-----------------------------------------------------------------------------
844 
846 {
847  LOGMESSAGE << "Audio removed" << list;
848 
849 }
850 
851 
852 //-----------------------------------------------------------------------------
853 // Private slot: The list of availabel devices has changed (test)
854 //-----------------------------------------------------------------------------
859 
861 {
862  LOGMESSAGE << "List of audio devices changed:" << list;
863  for (auto &e : list) e = shorten(e);
864  list.prepend(tr("[Choose output device]"));
865  QStringList devices = mAudioOutput.getListOfDevices();
867  int deviceIndex = devices.indexOf(parameters.deviceName);
868  emit setAudioDeviceList (list,deviceIndex+1);
869 
870  QStringList model;
871  for (auto &e : parameters.supportedSampleRates) model << QString::number(e);
872  int index = parameters.supportedSampleRates.indexOf(parameters.sampleRate);
873  emit setAudioSampleRates(model,index);
874 }
875 
876 
877 //-----------------------------------------------------------------------------
878 // Slot: on current audio device parameters changed
879 //-----------------------------------------------------------------------------
883 
885 {
886  LOGMESSAGE << "List of audio parameters changed.";
888  LOGMESSAGE << "DEVICE =" << parameters.deviceName << " SR =" << parameters.sampleRate;
889  QStringList model;
890  for (auto &e : parameters.supportedSampleRates) model << QString::number(e);
891  int index = parameters.supportedSampleRates.indexOf(parameters.sampleRate);
892  emit setAudioSampleRates(model,index);
893 }
894 
895 
896 //-----------------------------------------------------------------------------
897 // Slot: on audio connection established
898 //-----------------------------------------------------------------------------
903 
905 {
906  LOGMESSAGE << "Audio connected = " << success;
908  QString dev = parameters.deviceName;
909  if (dev.size()>0 and success) dev = shorten(dev);
910  else dev = tr("No device connected");
911  emit setAudioDeviceName(dev);
912 }
913 
914 
915 //-----------------------------------------------------------------------------
916 // Load a Midi file
917 //-----------------------------------------------------------------------------
922 
923 bool Application::loadMidiFile (QString filename)
924 {
925  LOGMESSAGE << "Trying to load Midi file" << filename;
926  QFile midifile (filename);
927  if (midifile.exists())
928  {
929  mMidiPlayer.loadFile(filename,true);
930  return true;
931  }
932  else
933  {
934  LOGWARNING << "MIDI File" << filename << "does not exist";
935  return false;
936  }
937 }
938 
939 
940 //-----------------------------------------------------------------------------
941 // Debug: Show error message on mobile
942 //-----------------------------------------------------------------------------
948 
949 void Application::mobileMessage(QString msg)
950 {
951  emit sendMobileMessage(msg);
952  qDebug() << "MOBILE ERROR MESSAGE" << msg;
953 }
954 
955 
956 //-----------------------------------------------------------------------------
957 // Slot: Closed Midi feedback loop discovered
958 //-----------------------------------------------------------------------------
962 
964 {
966  LOGWARNING << "Received signal about a closed Midi feedback loop";
967  // TODO message
968 }
969 
970 
971 //-----------------------------------------------------------------------------
972 // Slot: Closed Midi feedback loop discovered
973 //-----------------------------------------------------------------------------
977 
979 {
981 }
982 
983 
984 //-----------------------------------------------------------------------------
985 // Slot: Reset Audio Parameters
986 //-----------------------------------------------------------------------------
990 
992 {
993  int buffersize = INT_BUFFERSIZE;
994  int packetsize = INT_PACKETSIZE;
995 
996  auto parameters = mAudioOutput.getActualDeviceParameters();
997 
998  LOGMESSAGE << "Reset buffer size:" << buffersize;
999  parameters.bufferSize = buffersize;
1000  mSettings.setValue("audiooutput/buffersize",buffersize);
1001 
1002  LOGMESSAGE << "Reset packet size:" << packetsize;
1003  mSoundGenerator.setMaxPacketSize(packetsize);
1004  mSettings.setValue("audiooutput/packetsize",packetsize);
1005 
1006  mAudioOutput.setWantedParameters(parameters);
1007  emit connectAudioDevice(true);
1008  emit setAudioBufferSizes (buffersize,packetsize);
1009 }
1010 
1011 
1012 //-----------------------------------------------------------------------------
1013 // Debug: Show error message on mobile
1014 //-----------------------------------------------------------------------------
1016 
1018 
1019 void mobileError(QString msg)
1020 {
1021  globalApplicationPointer->mobileMessage(QString::number(mobileErrorCounter++) + ": " + msg);
1022 }
1023 
1024 
1025 
1026 // TODO Importer workaround:
1027 #include "instrument/wave.h"
void stop()
Stop the application and its components.
QSettings mSettings
Definition: application.h:151
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:174
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:161
bool loadMidiFile(QString filename)
Load a Midi file.
bool start() override final
Public slot: Start the tuner, starting the tuner thread.
Definition: tuner.cpp:92
bool mSuspended
Definition: application.h:175
bool stop()
Stop the microtonal converter.
double mLastEmittedPitchProgression
Definition: application.h:176
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:220
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:166
int mobileErrorCounter
void handleApplicationStates(Qt::ApplicationState state)
Function executed when application state changes (platform-dependent) Takes action if the state of th...
void play()
Play startup sound.
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:44
QString deviceName
Name of the audio device.
void onAudioDevicesRemoved(QStringList list)
Private slot: An audio device has been removed (test)
void setAudioDeviceName(QVariant name)
void start(bool forced)
Start the downloading process in the background.
Definition: downloader.cpp:112
bool init() override final
Initialize the Tuner.
Definition: tuner.cpp:66
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)
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
void loadFile(QString filename, bool autostart=false)
Load a midi file (*.mid) from disk.
Definition: midiplayer.cpp:88
Downloader mDownloader
Definition: application.h:156
void openFile(QString fileName, bool autostart)
void emitAveragePitchProgression(double pitchProgression)
Emit the newly calculated average pitch progression.
QApplication * pApplication
Definition: application.h:148
void onConnectionSuccessfullyEstablished(bool success)
Private slot: on audio connection established.
FileOpenDialog mFileOpenDialog
Definition: application.h:157
void signalSoftPedal(bool pressed)
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:167
void receiveMidiEvent(const QMidiMessage &event)
Definition: midihandler.cpp:56
QTranslator mQtTranslator
Definition: application.h:154
Sampler & getSampler()
void disableScreenSaver()
Definition: application.h:113
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:169
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:159
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:164
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:263
bool mRestartRequest
Definition: application.h:153
int bufferSize
Buffer size of the device if applicable.
SoundGenerator mSoundGenerator
Definition: application.h:165
void resume()
Resume from suspend mode.
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:149
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:162
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:56
void setAudioDeviceList(QVariant list, QVariant index)
void setSoftPedal(bool pressed)
void suspend()
Suspend the microtonal converter.
QString mLocale
Definition: application.h:152
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:163
QList< int > supportedSampleRates
List of supported sample rates.
void reInitializeConvertedMidiStream()
Slot: Re-initialize the output stream.
QTranslator mAppTranslator
Definition: application.h:155
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:242
void signalSustainPedal(bool pressed)
void setWantedParameters(const AudioParameters &parameters)
Set the wanted audio device parameters.
Definition: audiobase.cpp:100
LogFile mTuningLog
Definition: application.h:168
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:51