QSet<int> SpectrumAnalyzer::analyzeFT(int range, const QVector<float> &data) { const float average = std::accumulate(data.begin(), data.end(), .0f) / data.size(); const float threshold = qMax(50 * average, .1f * data.size()); QSet<int> pressedKeys; for (int i = 1; i < data.size() / 2; ++i) { if (isPeak(&data[i], threshold) && !isPeak(&data[i/2], threshold)) { const float freq = float(m_sampleRate) * i / data.size(); const int nTasto = qRound(12 * log2(freq / 440) + 48); if (nTasto >= m_ranges[range]->firstKey && nTasto <= m_ranges[range]->lastKey) pressedKeys.insert(nTasto); } } emit spectrumAvailable(range, data, threshold); return pressedKeys; }
// constructor: warm up all stuff MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) //,audioInfo(QAudioDeviceInfo::defaultInputDevice()) { // draws the ui ui->setupUi(this); // test for saving settings QCoreApplication::setOrganizationName("Agostinho"); /** some settings attempt */ QSettings settings; /*!<aloha */ settings.setValue("alo","maria"); // defines sample size equals to spectrum size sample.resize(SPECSIZE); // threads are as separate processes running within the same // program. for fft calculation, it is better to move it // to another thread to make the calcs faster. // moreover, it will not slow down the ui // fftThread = new QThread(this); calculator = new FFTCalc(); // calculator->moveToThread(fftThread); // launches the new media player player = new QMediaPlayer(); // starts a new playlist playlist = new QMediaPlaylist(); // starts the playlist model playlistModel = new PlaylistModel(this); // tell playlistmodel where is the playlist playlistModel->setPlaylist(playlist); // attach the listView to the playlistModel ui->listViewPlaylist->setModel(playlistModel); // set current index to the first element ui->listViewPlaylist->setCurrentIndex(playlistModel->index(playlist->currentIndex(), 0)); loadPlaylist(); // attachs the playlist to the player player->setPlaylist(playlist); // playlist plays in loop mode. It restarts after last song has finished playing. playlist->setPlaybackMode(QMediaPlaylist::Loop); // this allow the user to select the media it wants to play connect(ui->listViewPlaylist, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(goToItem(QModelIndex))); // if some metadata changed for media, display it somewhere // it seems not work on windows // but works for linux :) connect(player,SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); // the media status changed (new stream has arrived) connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus))); // the user selected a new position on music to play // perharps using some scrollbar connect(this,SIGNAL(positionChanged(qint64)), player,SLOT(setPosition(qint64))); connect(player,SIGNAL(volumeChanged(int)), ui->control,SLOT(onVolumeChanged(int))); connect(player,SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(mediaStateChanged(QMediaPlayer::State))); // that is the audio probe object that "listen to" // the music. It will help with fft stuff probe = new QAudioProbe(); // fft is delivered using a QVector<double> but // signal/slot scheme does not recognizes this type by default // therefore, we have to register it qRegisterMetaType< QVector<double> >("QVector<double>"); // here goes the control unit event handlers connect(ui->control, SIGNAL(playPause()), this, SLOT(playPause())); connect(ui->control, SIGNAL(prev()), this, SLOT(prev())); connect(ui->control, SIGNAL(next()), this, SLOT(next())); connect(this, SIGNAL(playPauseChanged(bool)), ui->control,SLOT(onPlayerStateChanged(bool))); // when the music position changes on player, it has to be // informed to the control unit to redraw it ui connect(player, SIGNAL(positionChanged(qint64)), ui->control,SLOT(onElapsedChanged(qint64))); // fft goes here... // if a new audio buffer is ok, we have to make some // calcs (fft) to display the spectrum connect(probe, SIGNAL(audioBufferProbed(QAudioBuffer)), this, SLOT(processBuffer(QAudioBuffer))); // when fft is available, we deliver it to // the visualization widget connect(this, SIGNAL(spectrumChanged(QVector<double>&)), ui->visualizer,SLOT(loadSamples(QVector<double>&))); // communicate the left and right audio levels... // ...mean levels connect(this, SIGNAL(levels(double,double)), ui->visualizer,SLOT(loadLevels(double,double))); // when fft is available, we deliver it to // the visualization widget //connect(this, SIGNAL(spectrumChanged(QVector<double>&)), // ui->glVisualizer,SLOT(loadSamples(QVector<double>&))); // communicate the left and right audio levels... // ...mean levels //connect(this, SIGNAL(levels(double,double)), // ui->glVisualizer,SLOT(loadLevels(double,double))); // if the user selected a new position on stream to play // we have to tell it to the player connect(ui->control, SIGNAL(elapsedSelected(qint64)), player, SLOT(setPosition(qint64))); // changing audio volume connect(ui->control, SIGNAL(volumeSelected(int)), player, SLOT(setVolume(int))); // calculator is the thead that calcs the ffts we need to display // every time a new spectrum is available, the calculator // emits a calculatedSpectrum signal connect(calculator, SIGNAL(calculatedSpectrum(QVector<double>)), this, SLOT(spectrumAvailable(QVector<double>))); connect(ui->library,SIGNAL(addMediaToPlayList(QString)), SLOT(onAddMediaToPlayList(QString))); // tells the probe what to probe probe->setSource(player); // load directories to library connect(ui->actionLoadDirectory,SIGNAL(triggered()),this,SLOT(onAddFolderToLibrary())); // load a single file to library connect(ui->actionLoadFile,SIGNAL(triggered()),this,SLOT(loadMedia())); // it connects the signals emiteds via the visualizer to the buttons (ui->control) and the lightCycle(ui->widgetInfo) connect(ui->visualizer,SIGNAL(trocaCor(QColor)),ui->control,SLOT(onColorChanged(QColor))); connect(ui->visualizer,SIGNAL(trocaCor(QColor)),ui->widgetInfo,SLOT(changedColor(QColor))); //this->setStyleSheet(QString("QMainWindow {background-color: black}")); }