// Copyright 2004 "Gilles Degottex" // This file is part of "fmit" // "fmit" is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // "fmit" is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "CustomInstrumentTunerForm.h" #include #include using namespace std; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Music; #include "modules/View.h" CustomInstrumentTunerForm::CustomInstrumentTunerForm() : m_capture_thread("fmit") , m_timer_refresh(this, "m_timer_refresh") , m_algo_combedfft(NULL) , m_range_filter(&m_dummy_range_filter) , m_quantizer(&m_latency_quantizer) , m_settings("gillesdegottex.ch", "fmit", "009700") // not necessarily equal to the soft version { View::s_settings = &m_settings; m_settings.add(m_config_form.ui_chkFullScreen); m_settings.add(m_config_form.ui_chkAutoSaveOnExit); m_settings.add(m_config_form.ui_chkShowA4Offset); m_settings.add(m_config_form.ui_cbTuning); m_settings.add(m_config_form.ui_cbTonality); m_settings.add(m_config_form.ui_cbNotesName); m_settings.add(ui_spinAFreq); m_settings.add(ui_spinA3Offset); m_settings.add(m_config_form.ui_chkAutoDetect); #ifdef CAPTURE_JACK m_settings.add(m_config_form.ui_chkJACKAutoConnect); m_settings.add(m_config_form.ui_txtJACKSourcePort); #endif #ifdef CAPTURE_ALSA m_settings.add(m_config_form.ui_chkALSASamplingRateMax); m_settings.add(m_config_form.ui_spinALSASamplingRate); m_settings.add(m_config_form.ui_chkALSAMixMultipleChannels); m_settings.add(m_config_form.ui_txtALSAPCMName); #endif #ifdef CAPTURE_OSS m_settings.add(m_config_form.ui_chkOSSSamplingRateMax); m_settings.add(m_config_form.ui_spinOSSSamplingRate); m_settings.add(m_config_form.ui_chkOSSMixMultipleChannels); m_settings.add(m_config_form.ui_txtOSSPCMName); #endif #ifdef CAPTURE_PORTAUDIO m_settings.add(m_config_form.ui_chkPortAudioSamplingRateMax); m_settings.add(m_config_form.ui_spinPortAudioSamplingRate); m_settings.add(m_config_form.ui_chkPortAudioMixMultipleChannels); #endif m_settings.add(m_config_form.ui_spinRefreshTime); m_settings.add(m_config_form.ui_spinMinHT); m_settings.add(m_config_form.ui_spinMaxHT); m_settings.add(m_config_form.ui_grpRangeFiltering); m_settings.add(m_config_form.ui_rdRangeFilteringRectangular); m_settings.add(m_config_form.ui_rdRangeFilteringFIR); m_settings.add(m_config_form.ui_spinVolumeTreshold); m_settings.add(m_config_form.ui_spinWindowSizeFactor); m_settings.add(m_config_form.ui_chkAlgoUseSubHarmTresh); m_settings.add(m_config_form.ui_spinCombedFFTAudibilityRatio); m_settings.add(m_config_form.up_grpFreqRefinement); m_settings.add(m_config_form.ui_rdUseFreqRefinement); m_settings.add(m_config_form.ui_spinFreqRefinMaxHarm); m_settings.add(m_config_form.ui_rdUseTimeRefinement); m_settings.add(m_config_form.ui_spinTimeRefinMaxPeriod); m_settings.add(m_config_form.ui_grpQuantizer); m_settings.add(m_config_form.ui_spinErrorLatency); m_algo_combedfft = new CombedFT(); for(int i=0; iinsertItem(m_capture_thread.getTransports()[i]->getName()); if(m_capture_thread.getTransports().empty()) QMessageBox::critical(this, "Error", "Please compile me with a capture system ..."); if(m_capture_thread.getTransports().size()==1) { m_config_form.ui_lblSelectedCaptureSystem->hide(); m_config_form.ui_btnAutoDetect->hide(); m_config_form.ui_chkAutoDetect->hide(); m_config_form.ui_cbTransports->hide(); } m_config_form.ui_grpALSA->hide(); m_config_form.ui_grpJACK->hide(); m_config_form.ui_grpPortAudio->hide(); m_config_form.ui_grpOSS->hide(); ui_lblA3Offset->hide(); ui_spinA3Offset->hide(); connect(&m_capture_thread, SIGNAL(samplingRateChanged(int)), this, SLOT(samplingRateChanged(int))); connect(&m_capture_thread, SIGNAL(errorRaised(const QString&)), this, SLOT(errorRaised(const QString&))); connect(&m_capture_thread, SIGNAL(transportChanged(const QString&)), this, SLOT(transportChanged(const QString&))); connect(&m_latency_quantizer, SIGNAL(noteStarted(double,double)), this, SLOT(noteStarted(double,double))); connect(&m_latency_quantizer, SIGNAL(noteFinished(double,double)), this, SLOT(noteFinished(double,double))); connect(&m_dummy_quantizer, SIGNAL(noteStarted(double,double)), this, SLOT(noteStarted(double,double))); connect(&m_dummy_quantizer, SIGNAL(noteFinished(double,double)), this, SLOT(noteFinished(double,double))); m_dialTune = new DialView(centralWidget()); ui_dialTuneLayout->addWidget(m_dialTune); m_glGraph = new GLGraph("Graph", centralWidget()); connect(m_glGraph->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); connect(m_glGraph->setting_spinMaxHeight, SIGNAL(valueChanged(int)), this, SLOT(update_views())); m_glGraph->setting_show->addTo(ui_tbViews); ui_graphLayout->addWidget(m_glGraph); m_glErrorHistory = new GLErrorHistory(centralWidget()); connect(m_glErrorHistory->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); m_glErrorHistory->setting_show->addTo(ui_tbViews); ui_errorLayout->addWidget(m_glErrorHistory); // link scales connect(m_dialTune->setting_spinScale, SIGNAL(valueChanged(int)), m_glErrorHistory->setting_spinScale, SLOT(setValue(int))); connect(m_glErrorHistory->setting_spinScale, SIGNAL(valueChanged(int)), m_dialTune->setting_spinScale, SLOT(setValue(int))); connect(m_dialTune->setting_useCents, SIGNAL(toggled(bool)), m_glErrorHistory->setting_useCents, SLOT(setOn(bool))); connect(m_glErrorHistory->setting_useCents, SIGNAL(toggled(bool)), m_dialTune->setting_useCents, SLOT(setOn(bool))); m_glVolumeHistory = new GLVolumeHistory(centralWidget()); connect(m_config_form.ui_spinVolumeTreshold, SIGNAL(valueChanged(int)), m_glVolumeHistory, SLOT(setVolumeTreshold(int))); connect(m_glVolumeHistory->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); m_glVolumeHistory->setting_show->addTo(ui_tbViews); ui_volumeLayout->addWidget(m_glVolumeHistory); // link keep settings connect(ui_btnKeepErrorHistory, SIGNAL(toggled(bool)), m_glErrorHistory->setting_keep, SLOT(setOn(bool))); connect(m_glErrorHistory->setting_keep, SIGNAL(toggled(bool)), m_glVolumeHistory->setting_keep, SLOT(setOn(bool))); connect(m_glErrorHistory->setting_keep, SIGNAL(toggled(bool)), ui_btnKeepErrorHistory, SLOT(setOn(bool))); m_glSample = new GLSample(centralWidget()); connect(m_glSample->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); m_glSample->setting_show->addTo(ui_tbViews); ui_sampleLayout->addWidget(m_glSample); m_glFreqStruct = new GLFreqStruct(centralWidget()); connect(m_glFreqStruct->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); m_glFreqStruct->setting_show->addTo(ui_tbViews); ui_formantsLayout->addWidget(m_glFreqStruct); m_glFT = new GLFT(centralWidget()); connect(m_glFT->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); m_glFT->setting_show->addTo(ui_tbViews); ui_FT->addWidget(m_glFT); m_microtonalView = new MicrotonalView(centralWidget()); connect(m_microtonalView->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); connect(m_microtonalView, SIGNAL(tuningFreqChanged(float)), this, SLOT(tuningFreqChanged(float))); m_microtonalView->setting_show->addTo(ui_tbViews); ui_microtonalLayout->addWidget(m_microtonalView); m_glStatistics = new GLStatistics(centralWidget()); connect(m_glStatistics->setting_show, SIGNAL(toggled(bool)), this, SLOT(update_views())); m_glStatistics->setting_show->addTo(ui_tbViews); ui_microtonalLayout->addWidget(m_glStatistics); connect(m_dialTune->setting_spinScale, SIGNAL(valueChanged(int)), m_glStatistics->setting_spinScale, SLOT(setValue(int))); connect(m_glStatistics->setting_spinScale, SIGNAL(valueChanged(int)), m_dialTune->setting_spinScale, SLOT(setValue(int))); connect(m_dialTune->setting_useCents, SIGNAL(toggled(bool)), m_glStatistics->setting_useCents, SLOT(setOn(bool))); connect(m_glStatistics->setting_useCents, SIGNAL(toggled(bool)), m_dialTune->setting_useCents, SLOT(setOn(bool))); connect(m_dialTune->setting_showTolerance, SIGNAL(toggled(bool)), m_glStatistics->setting_showTolerance, SLOT(setOn(bool))); connect(m_glStatistics->setting_showTolerance, SIGNAL(toggled(bool)), m_dialTune->setting_showTolerance, SLOT(setOn(bool))); connect(m_config_form.buttonOk, SIGNAL(clicked()), this, SLOT(configure_ok())); connect(m_config_form.ui_btnRestoreFactorySettings, SIGNAL(clicked()), this, SLOT(restoreFactorySettings())); connect(m_config_form.ui_spinMinHT, SIGNAL(valueChanged(int)), this, SLOT(noteRangeChanged())); connect(m_config_form.ui_spinMaxHT, SIGNAL(valueChanged(int)), this, SLOT(noteRangeChanged())); connect(m_config_form.ui_cbTuning, SIGNAL(highlighted(int)), this, SLOT(noteRangeChanged())); connect(m_config_form.ui_cbTonality, SIGNAL(highlighted(int)), this, SLOT(noteRangeChanged())); connect(m_config_form.ui_cbNotesName, SIGNAL(highlighted(int)), this, SLOT(noteRangeChanged())); connect(m_config_form.ui_btnAutoDetect, SIGNAL(clicked()), this, SLOT(autoDetectTransport())); connect(m_config_form.ui_cbTransports, SIGNAL(activated(const QString&)), this, SLOT(selectTransport(const QString&))); connect(m_config_form.ui_chkALSAMixMultipleChannels, SIGNAL(toggled(bool)), &m_capture_thread, SLOT(setMixMultipleChannels(bool))); connect(m_config_form.ui_chkOSSMixMultipleChannels, SIGNAL(toggled(bool)), &m_capture_thread, SLOT(setMixMultipleChannels(bool))); connect(m_config_form.ui_chkPortAudioMixMultipleChannels, SIGNAL(toggled(bool)), &m_capture_thread, SLOT(setMixMultipleChannels(bool))); loadSettings(); if(m_config_form.ui_chkAutoDetect->isChecked()) m_capture_thread.autoDetectTransport(); configure_ok(); if(m_config_form.ui_chkFullScreen->isChecked()) toggleFullScreen(); m_time_refresh_views.start(); m_time_refresh.start(); m_time.start(); connect((QObject*)&m_timer_refresh, SIGNAL(timeout()), this, SLOT(refresh())); m_timer_refresh.start(m_config_form.ui_spinRefreshTime->value()); } void CustomInstrumentTunerForm::transportChanged(const QString& name) { selectTransport(name); if(m_capture_thread.getCurrentTransportIndex()!=m_config_form.ui_cbTransports->currentItem()) m_config_form.ui_cbTransports->setCurrentItem(m_capture_thread.getCurrentTransportIndex()); } void CustomInstrumentTunerForm::selectTransport(const QString& name) { m_config_form.ui_grpALSA->hide(); m_config_form.ui_grpJACK->hide(); m_config_form.ui_grpPortAudio->hide(); m_config_form.ui_grpOSS->hide(); if(name=="ALSA") m_config_form.ui_grpALSA->show(); else if(name=="JACK") m_config_form.ui_grpJACK->show(); else if(name=="PortAudio") m_config_form.ui_grpPortAudio->show(); else if(name=="OSS") m_config_form.ui_grpOSS->show(); } void CustomInstrumentTunerForm::autoDetectTransport() { m_capture_thread.autoDetectTransport(); // here transportChanged will be called } void CustomInstrumentTunerForm::toggleFullScreen() { static bool fs = true; if(fs) { m_config_form.ui_chkFullScreen->setChecked(true); showFullScreen(); } else { m_config_form.ui_chkFullScreen->setChecked(false); showNormal(); } fs = !fs; } void CustomInstrumentTunerForm::noteRangeChanged() { // cerr << "CustomInstrumentTunerForm::noteRangeChanged" << endl; m_config_form.ui_txtMinHT->setText(h2n(m_config_form.ui_spinMinHT->value())+" = "+QString::number(h2f(m_config_form.ui_spinMinHT->value()))+" hz"); m_config_form.ui_txtMaxHT->setText(h2n(m_config_form.ui_spinMaxHT->value())+" = "+QString::number(h2f(m_config_form.ui_spinMaxHT->value()))+" hz"); } void CustomInstrumentTunerForm::errorRaised(const QString& error) { // cerr << "CustomInstrumentTunerForm::errorRaised " << error << endl; statusBar()->message(QString("ERROR: ")+error); ui_lblSoundStability->setBackgroundColor(QColor(180,74,74)); } void CustomInstrumentTunerForm::samplingRateChanged(int sampling_rate) { // cerr << "CustomInstrumentTunerForm::samplingRateChanged " << sampling_rate << endl; Music::SetSamplingRate(sampling_rate); m_rect_range_filter.reset(int(GetSamplingRate()/h2f(GetSemitoneMin()))); if(m_config_form.ui_cbTransports->currentText()=="JACK") m_config_form.ui_lblJACKSamplingRate->setText(QString::number(sampling_rate)); } void CustomInstrumentTunerForm::ui_spinAFreq_valueChanged(int AFreq) { double A = AFreq; if(m_config_form.ui_chkShowA4Offset->isOn()) A = h2f(ui_spinA3Offset->value()*1/100.0f, A); Music::SetAFreq(A); // cerr << A << endl; } void CustomInstrumentTunerForm::ui_spinAOffset_valueChanged(int offset) { double A = ui_spinAFreq->value(); if(m_config_form.ui_chkShowA4Offset->isOn()) A = h2f(offset*1/100.0f, ui_spinAFreq->value()); Music::SetAFreq(A); // cerr << A << endl; } void CustomInstrumentTunerForm::tuningFreqChanged(float freq) { // cerr << "CustomInstrumentTunerForm::tuningFreqChanged " << freq << endl; if(freq==0.0f) { if(m_compared_freq!=0.0f) { ui_txtNoteFreq->display(m_compared_freq); ui_txtNote->setText(h2n(f2h(m_compared_freq))); } } else { m_compared_freq = freq; ui_txtNoteFreq->display(int(freq*100)/100.0f); ui_txtNote->setText(m_microtonalView->getTuningNoteName()); } m_quantizer->reset(); // m_dialTune->setError(-10.0f); } void CustomInstrumentTunerForm::pause(bool on) { m_capture_thread.togglePause(on); if(on) m_timer_refresh.stop(); else m_timer_refresh.start(m_config_form.ui_spinRefreshTime->value()); } void CustomInstrumentTunerForm::refresh() { double elapsed_time = m_time_refresh.elapsed(); m_time_refresh.start(); QColor capture_failed_color(180,74,74); QColor prb_color(208,146,0); QColor empty_color(128,128,128); QColor ok_color(83,165,105); // 1/{time between refresh} = {nb refresh by seconds} // limit the nb new data by fs/{nb refresh by seconds} // add 1 to {nb refresh by second} to eventualy recover lags int limit = int( m_capture_thread.getSamplingRate() / (1.0/(m_config_form.ui_spinRefreshTime->value()/1000.0) - 1)); // cerr << "REFRESH "; m_capture_thread.lock(); double max_amplitude = 0.0; int nb_new_data = 0; while(!m_capture_thread.m_values.empty() && (m_capture_thread.m_values.size()>m_capture_thread.getPacketSizeSinceLastLock() || nb_new_dataaddValue(value); if(m_glFT) m_glFT->buff.push_front(value); nb_new_data++; } m_capture_thread.unlock(); // cerr << endl; int max_size = max(m_range_filter->getLength(), max(m_glGraph->getLength(), m_algo_combedfft->getMinSize())); while(!m_queue.empty() && int(m_queue.size())>max_size) m_queue.pop_back(); // refresh graph data m_glGraph->refreshGraph(); // TODO refresh the view each time ?? m_glFT->refreshGraph(); // ------- Analysis stage ------- // if something goes wrong in the capture system if(nb_new_data==0 || m_algo_combedfft==NULL || elapsed_time>8*m_config_form.ui_spinRefreshTime->value()) ui_lblSoundStability->setBackgroundColor(capture_failed_color); else { m_algo_combedfft->apply(m_queue); double max_component = 20*log10(m_algo_combedfft->getComponentsMax()); ui_pgbVolume->setProgress(100+int(max_component)); double freq = 0.0; if(m_algo_combedfft->hasNoteRecognized()) freq = m_algo_combedfft->getFondamentalFreq(); double freq_rel = freq*m_algo_combedfft->m_plan.in.size()/double(GetSamplingRate()); if(freq_rel<1 || freq_rel>(m_algo_combedfft->m_plan.out.size()/2)) freq = 0.0; // frequency refinement if(freq>0.0 && m_config_form.up_grpFreqRefinement->isChecked()) { if(m_config_form.ui_rdUseFreqRefinement->isChecked()) { freq = FundFreqRefinementOfHarmonicStruct(m_algo_combedfft->m_plan.out, freq, m_config_form.ui_spinFreqRefinMaxHarm->value(), m_algo_combedfft->getZeroPaddingFactor()); } else if(m_config_form.ui_rdUseTimeRefinement->isChecked()) { double period = GetAveragePeriodFromApprox(m_queue, int(GetSamplingRate()/freq), m_config_form.ui_spinTimeRefinMaxPeriod->value()); if(period>0.0) freq = GetSamplingRate()/period; } } // cerr << "2) test freq=" << m_test_freq <quantize(freq); if(!m_quantizer->isPlaying()) ui_lblSoundStability->setBackgroundColor(empty_color); else { if(max_amplitude>=1.0) ui_lblSoundStability->setBackgroundColor(prb_color); else ui_lblSoundStability->setBackgroundColor(ok_color); m_freq = m_quantizer->getAverageFrequency(); m_error = f2hf(m_freq, m_compared_freq); // refresh error m_glErrorHistory->addError(m_error); m_dialTune->setError(m_error); m_dialTune->m_avg_error = m_glErrorHistory->m_notes.back().avg_err; m_dialTune->m_min_error = m_glErrorHistory->m_notes.back().min_err; m_dialTune->m_max_error = m_glErrorHistory->m_notes.back().max_err; ui_txtFreq->display(m_freq); // refresh intonal tuning cursor m_microtonalView->setAFreq(Music::GetAFreq()); m_microtonalView->updateCursor(m_freq); // volume m_glVolumeHistory->addVolume(max_component); // refresh sample data refresh_data_sample(); // refresh formants data refresh_data_harmonics(); m_glStatistics->addNote(f2h(m_compared_freq), m_error); } } if(m_time_refresh_views.elapsed()>50) // 20 images/second max refresh_views(); } void CustomInstrumentTunerForm::noteStarted(double freq, double dt) { // cerr << "CustomInstrumentTunerForm::noteStarted " << freq << "," << dt << endl; // set the compared freq if(m_microtonalView->setting_show->isOn() && m_microtonalView->hasTuningFreqSelected()) m_compared_freq = m_microtonalView->getTuningFreq(); else m_compared_freq = m_quantizer->getCenterFrequency(); // h2f(f2h(freq)); if(m_microtonalView->setting_show->isOn() && m_microtonalView->hasTuningFreqSelected()) { ui_txtNoteFreq->display(int(m_microtonalView->getTuningFreq()*100)/100.0); ui_txtNote->setText(m_microtonalView->getTuningNoteName()); if(m_microtonalView->m_selected_jivalue->is_ratio) { m_glErrorHistory->addNote(GLErrorHistory::Note(m_microtonalView->setting_selectedRoot, m_microtonalView->m_selected_jivalue->num, m_microtonalView->m_selected_jivalue->den)); m_glVolumeHistory->addNote(GLVolumeHistory::Note(m_microtonalView->setting_selectedRoot, m_microtonalView->m_selected_jivalue->num, m_microtonalView->m_selected_jivalue->den)); } else { m_glErrorHistory->addNote(GLErrorHistory::Note(m_microtonalView->setting_selectedRoot, m_microtonalView->m_selected_jivalue->cents)); m_glVolumeHistory->addNote(GLVolumeHistory::Note(m_microtonalView->setting_selectedRoot, m_microtonalView->m_selected_jivalue->cents)); } } else { ui_txtNoteFreq->display(m_compared_freq); ui_txtNote->setText(h2n(f2h(m_compared_freq))); m_glErrorHistory->addNote(GLErrorHistory::Note(f2h(m_compared_freq))); m_glVolumeHistory->addNote(GLVolumeHistory::Note(f2h(m_compared_freq))); } } void CustomInstrumentTunerForm::noteFinished(double freq, double dt) { m_compared_freq = 0.0; // cerr << "CustomInstrumentTunerForm::noteFinished " << freq << "," << dt << endl; } void CustomInstrumentTunerForm::refresh_data_sample() { if(m_freq==0.0f || !m_glSample->setting_show->isOn()) { m_glSample->clear(); return; } deque sample; GetWaveSample(m_queue, size_t(m_capture_thread.getSamplingRate()/m_freq), sample); m_glSample->add(m_time.elapsed(), sample); } void CustomInstrumentTunerForm::refresh_data_harmonics() { if(!(m_algo_combedfft!=NULL && m_freq>0.0f && m_glFreqStruct->setting_show->isOn())) return; vector harms = GetHarmonicStruct(m_algo_combedfft->m_plan.out, m_freq, m_glFreqStruct->m_components.size(), m_algo_combedfft->getZeroPaddingFactor()); m_glFreqStruct->m_components_max = 0.0; for(int i=0; im_components.size()) { m_glFreqStruct->m_components[harms[i].harm_number-1] = 20*log10(harms[i].mod/0.001); m_glFreqStruct->m_components_max = max(m_glFreqStruct->m_components_max, m_glFreqStruct->m_components[i]); } } } void CustomInstrumentTunerForm::refresh_views() { // cerr << "CustomInstrumentTunerForm::refresh_views " << endl; // m_dialTune->repaint(); if(m_glGraph->setting_show->isOn()) m_glGraph->updateGL(); if(m_glErrorHistory->setting_show->isOn()) m_glErrorHistory->updateGL(); if(m_glVolumeHistory->setting_show->isOn()) m_glVolumeHistory->updateGL(); if(m_microtonalView->setting_show->isOn()) m_microtonalView->update(); if(m_glSample->setting_show->isOn()) m_glSample->updateGL(); if(m_glFreqStruct->setting_show->isOn()) m_glFreqStruct->updateGL(); if(m_glFT->setting_show->isOn()) m_glFT->updateGL(); if(m_glStatistics->setting_show->isOn()) m_glStatistics->updateGL(); m_time_refresh_views.start(); } void CustomInstrumentTunerForm::keyPressEvent(QKeyEvent * e) { if(e->key()==Key_F) toggleFullScreen(); } void CustomInstrumentTunerForm::resizeEvent(QResizeEvent* e) { update_views(); InstrumentTunerForm::resizeEvent(e); } void CustomInstrumentTunerForm::update_views() { if( !m_glGraph->setting_show->isOn() && !m_glErrorHistory->setting_show->isOn() && !m_glVolumeHistory->setting_show->isOn() && !m_glSample->setting_show->isOn() && !m_glFreqStruct->setting_show->isOn() && !m_glFT->setting_show->isOn()) m_dialTune->setMaximumWidth(size().width()); else m_dialTune->setMaximumWidth(ui_rightLayout->minimumSize().width()); if(m_glGraph->setting_show->isOn() && !m_glErrorHistory->setting_show->isOn() && !m_glVolumeHistory->setting_show->isOn() && !m_glSample->setting_show->isOn() && !m_glFreqStruct->setting_show->isOn() && !m_glFT->setting_show->isOn()) m_glGraph->setMaximumHeight(size().height()); else m_glGraph->setMaximumHeight(m_glGraph->setting_spinMaxHeight->value()); if(!m_glErrorHistory->setting_show->isOn() && !m_glVolumeHistory->setting_show->isOn()) ui_btnKeepErrorHistory->hide(); else ui_btnKeepErrorHistory->show(); } void CustomInstrumentTunerForm::configure() { noteRangeChanged(); if(m_capture_thread.getCurrentTransportIndex()count()); m_config_form.ui_cbTransports->setCurrentItem(m_capture_thread.getCurrentTransportIndex()); #ifdef CAPTURE_JACK // TODO set descr m_config_form.ui_grpJACK->setTitle(m_capture_thread.getTransport("JACK")->getDescription()); m_config_form.ui_lblJACKSamplingRate->setText(QString::number(m_capture_thread.getSamplingRate())); #endif #ifdef CAPTURE_PORTAUDIO m_config_form.ui_grpPortAudio->setTitle(m_capture_thread.getTransport("PortAudio")->getDescription()); m_config_form.ui_spinPortAudioSamplingRate->setValue(m_capture_thread.getSamplingRate()); if(m_capture_thread.getTransport("PortAudio")) { try { PaError err; err = Pa_Initialize(); if(err != paNoError) throw QString("PortAudio: CustomInstrumentTunerForm::configure:Pa_Initialize ")+Pa_GetErrorText(err); int numDevices = Pa_GetDeviceCount(); int current_index = -1; m_config_form.ui_cbPortAudioDeviceName->clear(); m_config_form.ui_cbPortAudioDeviceName->insertItem("default"); const PaDeviceInfo* deviceInfo; for(int i=0; iinsertItem(QString(deviceInfo->name)); if(QString(deviceInfo->name)==m_capture_thread.getTransport("PortAudio")->getSource()) current_index = i+1; } m_config_form.ui_cbPortAudioDeviceName->setCurrentItem(current_index); } catch(QString error) { cerr << "CustomInstrumentTunerForm: ERROR: " << error << endl; } Pa_Terminate(); } #endif #ifdef CAPTURE_ALSA m_config_form.ui_grpALSA->setTitle(m_capture_thread.getTransport("ALSA")->getDescription()); m_config_form.ui_spinALSASamplingRate->setValue(m_capture_thread.getSamplingRate()); #endif #ifdef CAPTURE_OSS m_config_form.ui_grpOSS->setTitle(m_capture_thread.getTransport("OSS")->getDescription()); m_config_form.ui_spinOSSSamplingRate->setValue(m_capture_thread.getSamplingRate()); #endif m_config_form.adjustSize(); m_config_form.show(); } void CustomInstrumentTunerForm::configure_ok() { switch(m_config_form.ui_cbTuning->currentItem()) { case 0: SetTuning(CHROMATIC); break; case 1: SetTuning(WERCKMEISTER3); break; case 2: SetTuning(KIRNBERGER3); break; case 3: SetTuning(DIATONIC); break; case 4: SetTuning(MEANTONE); break; default: SetTuning(CHROMATIC); break; } if(m_config_form.ui_cbTonality->currentItem()==0) SetTonality(0); else if(m_config_form.ui_cbTonality->currentItem()==1) SetTonality(+2); else SetTonality(-3); if(m_config_form.ui_cbNotesName->currentItem()==0) SetNotesName(LOCAL_ANGLO); else SetNotesName(LOCAL_LATIN); m_microtonalView->notesNameChanged(); m_microtonalView->setAFreq(Music::GetAFreq()); SetSemitoneBounds(m_config_form.ui_spinMinHT->value(), m_config_form.ui_spinMaxHT->value()); ui_spinA3Offset->setShown(m_config_form.ui_chkShowA4Offset->isOn()); ui_lblA3Offset->setShown(m_config_form.ui_chkShowA4Offset->isOn()); // if(m_note!=-1000) // ui_txtNote->setText(h2n(m_note)); // m_dialTune->setError(-10.0f); // cerr << "b" << endl; // Capture #ifdef CAPTURE_ALSA if(m_config_form.ui_cbTransports->currentText()=="ALSA") { m_capture_thread.selectTransport("ALSA"); m_capture_thread.setSource(m_config_form.ui_txtALSAPCMName->text()); if(m_config_form.ui_chkALSASamplingRateMax->isChecked()) m_capture_thread.setSamplingRate(CaptureThread::SAMPLING_RATE_MAX); else m_capture_thread.setSamplingRate(m_config_form.ui_spinALSASamplingRate->value()); } #endif #ifdef CAPTURE_JACK if(m_config_form.ui_cbTransports->currentText()=="JACK") { m_capture_thread.selectTransport("JACK"); if(m_config_form.ui_chkJACKAutoConnect->isChecked()) m_capture_thread.setSource(m_config_form.ui_txtJACKSourcePort->text()); else m_capture_thread.setSource(""); m_config_form.ui_lblJACKSamplingRate->setText(QString::number(m_capture_thread.getSamplingRate())); } #endif #ifdef CAPTURE_PORTAUDIO if(m_config_form.ui_cbTransports->currentText()=="PortAudio") { m_capture_thread.selectTransport("PortAudio"); m_capture_thread.setSource(m_config_form.ui_cbPortAudioDeviceName->currentText()); if(m_config_form.ui_chkPortAudioSamplingRateMax->isChecked()) m_capture_thread.setSamplingRate(CaptureThread::SAMPLING_RATE_MAX); else m_capture_thread.setSamplingRate(m_config_form.ui_spinPortAudioSamplingRate->value()); } #endif #ifdef CAPTURE_OSS if(m_config_form.ui_cbTransports->currentText()=="OSS") { m_capture_thread.selectTransport("OSS"); m_capture_thread.setSource(m_config_form.ui_txtOSSPCMName->text()); if(m_config_form.ui_chkOSSSamplingRateMax->isChecked()) m_capture_thread.setSamplingRate(CaptureThread::SAMPLING_RATE_MAX); else m_capture_thread.setSamplingRate(m_config_form.ui_spinOSSSamplingRate->value()); } #endif m_timer_refresh.changeInterval(m_config_form.ui_spinRefreshTime->value()); // Views m_glGraph->m_treshold = pow(10, m_config_form.ui_spinVolumeTreshold->value()/20.0); m_glGraph->clearValues(); // cerr << "c" << endl; if(m_config_form.ui_grpRangeFiltering->isChecked()) { m_rect_range_filter.reset(int(GetSamplingRate()/h2f(GetSemitoneMin()))); // m_fir_range_filter.setImpulseResponse(fir1_highpass(int(GetSamplingRate()/h2f(GetSemitoneMin())), )); if(m_config_form.ui_rdRangeFilteringRectangular->isChecked()) m_range_filter = &m_rect_range_filter; else if(m_config_form.ui_rdRangeFilteringFIR->isChecked()) m_range_filter = &m_fir_range_filter; } else m_range_filter = &m_dummy_range_filter; m_algo_combedfft->setWindowFactor(m_config_form.ui_spinWindowSizeFactor->value()); // m_glFT->m_zp_factor = m_config_form.ui_spinWindowSizeFactor->value(); m_algo_combedfft->useAudibilityRatio(m_config_form.ui_chkAlgoUseSubHarmTresh->isChecked()); m_algo_combedfft->setAudibilityRatio(pow(10, -m_config_form.ui_spinCombedFFTAudibilityRatio->value()/20.0)); m_algo_combedfft->setAmplitudeTreshold(pow(10, m_config_form.ui_spinVolumeTreshold->value()/20.0)); m_algo_combedfft->setComponentTreshold(pow(10, m_config_form.ui_spinVolumeTreshold->value()/20.0)); // cerr << "d" << endl; // Quantizers m_quantizer->reset(); if(m_config_form.ui_grpQuantizer->isChecked()) { m_latency_quantizer.setLatency(m_config_form.ui_spinErrorLatency->value()); m_quantizer = &m_latency_quantizer; } else m_quantizer = &m_dummy_quantizer; // cerr << pow(10, -m_config_form.ui_spinCombedFFTAudibilityRatio->value()/20.0) << endl; if(!pauseAction->isOn() && !m_capture_thread.isCapturing()) m_capture_thread.startCapture(); } void CustomInstrumentTunerForm::saveSettings() { m_settings.save(); View::saveAll(); // views m_settings.writeEntry("width", width()); m_settings.writeEntry("height", height()); m_settings.writeEntry("ui_tbViews", ui_tbViews->isShown()); m_settings.writeEntry("ui_tbButtons", ui_tbButtons->isShown()); // sound capture m_settings.writeEntry(m_config_form.ui_cbTransports->name(), m_config_form.ui_cbTransports->currentText()); #ifdef CAPTURE_PORTAUDIO m_settings.writeEntry(m_config_form.ui_cbPortAudioDeviceName->name(), m_config_form.ui_cbPortAudioDeviceName->currentText()); #endif } void CustomInstrumentTunerForm::loadSettings() { m_settings.load(); View::loadAll(); // views resize(m_settings.readNumEntry("width", 800), m_settings.readNumEntry("height", 600)); ui_tbViews->setShown(m_settings.readBoolEntry("ui_tbViews", ui_tbViews->isShown())); ui_tbButtons->setShown(m_settings.readBoolEntry("ui_tbButtons", ui_tbButtons->isShown())); // sound capture QString saved_transport = m_settings.readEntry(m_config_form.ui_cbTransports->name(), ""); if(saved_transport!="") for(int i=0; icount(); i++) if(m_config_form.ui_cbTransports->text(i)==saved_transport) m_config_form.ui_cbTransports->setCurrentItem(i); #ifdef CAPTURE_PORTAUDIO // cerr << "read: " << m_settings.readEntry("ui_cbPortAudioDeviceName", "default") << endl; QString saved_device = m_settings.readEntry(m_config_form.ui_cbPortAudioDeviceName->name(), "default"); try { PaError err; err = Pa_Initialize(); if(err != paNoError) throw QString("PortAudio: CustomInstrumentTunerForm::loadSettings:Pa_Initialize ")+Pa_GetErrorText(err); int numDevices = Pa_GetDeviceCount(); int current_index = 0; m_config_form.ui_cbPortAudioDeviceName->clear(); m_config_form.ui_cbPortAudioDeviceName->insertItem("default"); const PaDeviceInfo* deviceInfo; for(int i=0; iinsertItem(QString(deviceInfo->name)); if(QString(deviceInfo->name)==saved_device) current_index = i+1; } if(current_indexcount()) m_config_form.ui_cbPortAudioDeviceName->setCurrentItem(current_index); } catch(QString error) { // cerr << "CustomInstrumentTunerForm: ERROR: " << error << endl; } Pa_Terminate(); #endif } void CustomInstrumentTunerForm::restoreFactorySettings() { if(QMessageBox::question(this, tr("Restore Factory Settings"), tr("This operation is NOT reversible.\nAre you sure you want to lose all your current settings ?"), QMessageBox::Yes, QMessageBox::No)==QMessageBox::Yes) { m_settings.clear(); View::clearAllSettings(); m_settings.removeEntry("width"); m_settings.removeEntry("height"); m_settings.removeEntry("ui_tbViews"); m_settings.removeEntry("ui_tbButtons"); m_settings.removeEntry(m_config_form.ui_cbPortAudioDeviceName->name()); QMessageBox::information(this, tr("Restore Factory Settings"), tr("You can now restart FMIT to get back factory settings"), QMessageBox::Ok, QMessageBox::NoButton); } } void CustomInstrumentTunerForm::helpAbout() { QString text; text = "

Free Music Instrument Tuner

"; text += tr("

Version ")+PACKAGE_VERSION; text += tr("

Website:

homepage: http://home.gna.org/fmit"); text += tr("

development site: http://gna.org/projects/fmit"); text += tr("

donation link: http://home.gna.org/fmit/donation.html"); text += tr("

Author:

Gilles Degottex [gilles.degottex@net2000.ch]"); #ifdef PACKAGER_STRING if(PACKAGER_STRING!="") text += tr("

Packager:

")+QString(PACKAGER_STRING).replace(QChar('<'),"[").replace(QChar('>'),"]"); #endif QDialog about_dlg(this); QTextEdit* textEdit1; QPushButton* pushButton1; QVBoxLayout* Form2Layout; QHBoxLayout* layout1; QSpacerItem* spacer1; QSpacerItem* spacer2; about_dlg.setName( tr("about_box") ); about_dlg.setCaption( tr("About Free Music Instrument Tuner") ); Form2Layout = new QVBoxLayout( &about_dlg, 11, 6, "Form2Layout"); textEdit1 = new QTextEdit( &about_dlg, "textEdit1" ); textEdit1->setText(text); textEdit1->setReadOnly(true); Form2Layout->addWidget( textEdit1 ); layout1 = new QHBoxLayout( 0, 0, 6, "layout1"); spacer1 = new QSpacerItem( 40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); layout1->addItem( spacer1 ); pushButton1 = new QPushButton( &about_dlg, "pushButton1" ); pushButton1->setText( tr( "OK" ) ); layout1->addWidget( pushButton1 ); connect(pushButton1, SIGNAL(clicked()), &about_dlg, SLOT(close())); spacer2 = new QSpacerItem( 40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum ); layout1->addItem( spacer2 ); Form2Layout->addLayout( layout1 ); about_dlg.resize( QSize(400, textEdit1->heightForWidth(400)+100) ); // about_dlg.clearWState( WState_Polished ); about_dlg.exec(); } CustomInstrumentTunerForm::~CustomInstrumentTunerForm() { if(m_config_form.ui_chkAutoSaveOnExit->isChecked()) saveSettings(); else { m_settings.beginGroup("Auto/"); m_settings.save(m_config_form.ui_chkAutoSaveOnExit); m_settings.endGroup(); } } /* bool displayInBrowser(const QString& theURL) { #ifdef _WIN32 //TODO replace with less buggy ShellExecuteEx? if ((unsigned int)::ShellExecute(qApp->mainWidget()->winId(),NULL,theURL,NULL,NULL,SW_SHOW) <= 32) { OFMessageBox::criticalMessageOK(QMessageBox::tr("Unable to display a web browser. Ensure that you have a web browser installed.")); } #else //TODO warn if netscape not installed QString aCommand("netscape "); aCommand += theURL; aCommand += " &"; if (system(aCommand) != 0) { OFMessageBox::criticalMessageOK(QMessageBox::tr("Unable to display a netscape browser. You need to have netscape installed and in the path.")); } return true; } */