From 731c14a4cbdf432d08941434a71f3c46ddfa604e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Sun, 15 Sep 2024 01:35:31 -0600 Subject: [PATCH 01/16] WIP: Fixing race condition on initial file load --- mediaplayer.cpp | 27 +++++++++++++++++++++++++++ mediaplayer.h | 1 + 2 files changed, 28 insertions(+) diff --git a/mediaplayer.cpp b/mediaplayer.cpp index 1c3d5ab..8150177 100644 --- a/mediaplayer.cpp +++ b/mediaplayer.cpp @@ -61,6 +61,8 @@ void MediaPlayer::setupAudioOutput() delete m_audioOutput; } m_audioOutput = new QAudioSink(m_format, this); + connect(m_audioOutput, &QAudioSink::stateChanged, this, &MediaPlayer::onOutputStateChanged); + m_audioOutput->setVolume(m_volume); emit volumeChanged(volume()); } @@ -292,6 +294,31 @@ void MediaPlayer::onAtEnd() ///////////////////////////////////////////////////////////////////// +void MediaPlayer::onOutputStateChanged(QAudio::State newState) +{ + qDebug() << "QAudioSink state change, new state:" << newState; + + QAudio::Error error = m_audioOutput->error(); + if(error != QAudio::NoError) { + qDebug() << "Audio Ouput error: " << error; + } + + switch(newState) { + case QAudio::IdleState: + if(error == QAudio::UnderrunError) { + // Handle race condition on initial loading + // Retry playing + qDebug() << "Retry playing!!!"; + this->stop(); + int timeout = 200; // msecs + QTimer::singleShot(timeout, this, &MediaPlayer::play); + } + break; + default: + break; + } +} + MediaPlayer::PlaybackState MediaPlayer::playbackState() const { return m_state; diff --git a/mediaplayer.h b/mediaplayer.h index da696a4..8509f8c 100644 --- a/mediaplayer.h +++ b/mediaplayer.h @@ -112,6 +112,7 @@ private slots: void onDurationChanged(qint64 duration); void onDecoderError(QAudioDecoder::Error error); void onAtEnd(); + void onOutputStateChanged(QAudio::State newState); signals: void playbackStateChanged(MediaPlayer::PlaybackState state); From a63777f74731a78a82ddb1fb9582f9e9d22c6b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Sun, 15 Sep 2024 02:24:39 -0600 Subject: [PATCH 02/16] WIP: Fixing playback glitches --- mediaplayer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mediaplayer.cpp b/mediaplayer.cpp index 8150177..cab096d 100644 --- a/mediaplayer.cpp +++ b/mediaplayer.cpp @@ -86,7 +86,8 @@ void MediaPlayer::clearAudioOutput() // AudioOutput devices (like speaker) will call this function to get new audio data qint64 MediaPlayer::readData(char* data, qint64 maxlen) { - QMutexLocker l(&readMutex); + qDebug() << "ReadDAta" << maxlen; + //QMutexLocker l(&readMutex); // Limit max len if(maxlen > MAX_AUDIO_STREAM_SAMPLE_SIZE) maxlen = MAX_AUDIO_STREAM_SAMPLE_SIZE; @@ -98,6 +99,7 @@ qint64 MediaPlayer::readData(char* data, qint64 maxlen) { // Copy bytes from buffer into data bytesRead = m_output.read(data, maxlen); + qDebug() << ">>> Byes read" << bytesRead; // Emmit newData event, for visualization if (maxlen > 0) @@ -166,8 +168,10 @@ void MediaPlayer::stop(bool stopAudioOutput) if(stopAudioOutput) m_audioOutput->stop(); // Clear buffers, avoids pops and clicks when playing after stopping - m_audioOutput->reset(); - this->reset(); + //m_audioOutput->reset(); + //this->reset(); + clearAudioOutput(); + setupAudioOutput(); setPosition(0); onPositionChanged(); @@ -453,6 +457,8 @@ void MediaPlayer::setPosition(qint64 position) if(target >= currentBufferSize) target = currentBufferSize - 1; if(target < 0) target = 0; + qDebug() << "Set position: " << target; + m_output.seek(target); } From b9dc106ed5934912b222812bcab4f6cd7eca4096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Sun, 15 Sep 2024 02:37:05 -0600 Subject: [PATCH 03/16] WIP: testing --- mediaplayer.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mediaplayer.cpp b/mediaplayer.cpp index cab096d..a830be9 100644 --- a/mediaplayer.cpp +++ b/mediaplayer.cpp @@ -86,8 +86,7 @@ void MediaPlayer::clearAudioOutput() // AudioOutput devices (like speaker) will call this function to get new audio data qint64 MediaPlayer::readData(char* data, qint64 maxlen) { - qDebug() << "ReadDAta" << maxlen; - //QMutexLocker l(&readMutex); + QMutexLocker l(&readMutex); // Limit max len if(maxlen > MAX_AUDIO_STREAM_SAMPLE_SIZE) maxlen = MAX_AUDIO_STREAM_SAMPLE_SIZE; @@ -99,7 +98,6 @@ qint64 MediaPlayer::readData(char* data, qint64 maxlen) { // Copy bytes from buffer into data bytesRead = m_output.read(data, maxlen); - qDebug() << ">>> Byes read" << bytesRead; // Emmit newData event, for visualization if (maxlen > 0) @@ -457,8 +455,6 @@ void MediaPlayer::setPosition(qint64 position) if(target >= currentBufferSize) target = currentBufferSize - 1; if(target < 0) target = 0; - qDebug() << "Set position: " << target; - m_output.seek(target); } From a7a1f190c405cb2ecde2bbc66298d0c1853a01a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Sun, 15 Sep 2024 22:18:02 -0600 Subject: [PATCH 04/16] Implemented max retries and resume from last position on retry --- README.md | 2 +- mediaplayer.cpp | 28 ++++++++++++++++++++++++++-- mediaplayer.h | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 375616f..fd2939d 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ pip install -r python/requirements.txt **Using Qt Creator:** -1. Open this project with Qt Creator (open player.pro in Qt Creator) +1. Open this project with Qt Creator (open CMakeLists.txt in Qt Creator) 2. Qt Creator should guide you setting up your paths and settings for building the proyect in your machine 3. You should be able to click the green "Play" icon in Qt Creator to build and run the app diff --git a/mediaplayer.cpp b/mediaplayer.cpp index a830be9..e1a4d19 100644 --- a/mediaplayer.cpp +++ b/mediaplayer.cpp @@ -9,6 +9,13 @@ #include #include +/* + * Max number of times the player will retry playing + * after a buffer underrun while loading the file + * before stopping + */ +#define MP_MAX_BUFFER_UNDERRUN_RETRIES 10 + MediaPlayer::MediaPlayer(QObject *parent) : QIODevice{parent}, m_input(&m_data), @@ -189,6 +196,7 @@ void MediaPlayer::clear() m_output.close(); isDecodingFinished = false; isInited = false; + bufferUnderrunRetries = 0; } // Is at the end of the file @@ -308,12 +316,28 @@ void MediaPlayer::onOutputStateChanged(QAudio::State newState) switch(newState) { case QAudio::IdleState: if(error == QAudio::UnderrunError) { + + if(this->bufferUnderrunRetries > MP_MAX_BUFFER_UNDERRUN_RETRIES) { + this->stop(); + qDebug() << "Buffer underrun: max retries reached"; + return; + } + this->bufferUnderrunRetries++; + // Handle race condition on initial loading // Retry playing - qDebug() << "Retry playing!!!"; + qint64 pos = this->position(); + qDebug() << "Retry playing from position: " << pos; + this->stop(); + + // Give some time for the buffer to fill int timeout = 200; // msecs - QTimer::singleShot(timeout, this, &MediaPlayer::play); + QTimer::singleShot(timeout, this, [=](){ + this->play(); + // Try resuming from previous position + this->setPosition(pos); + }); } break; default: diff --git a/mediaplayer.h b/mediaplayer.h index 8509f8c..2dea2a7 100644 --- a/mediaplayer.h +++ b/mediaplayer.h @@ -83,6 +83,7 @@ class MediaPlayer : public QIODevice bool isInited; bool isDecodingFinished; + qint8 bufferUnderrunRetries = 0; bool m_seekable = false; qint64 m_position = 0; From 03e13265e17c4bbc63c84de4da4c58a165535490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Sun, 15 Sep 2024 23:08:20 -0600 Subject: [PATCH 05/16] some cleanup --- .gitignore | 4 +++ doc/images/mediaplayerex.jpg | Bin 28825 -> 0 bytes doc/src/player.qdoc | 48 ----------------------------------- mediaplayer.cpp | 10 +++----- 4 files changed, 7 insertions(+), 55 deletions(-) delete mode 100644 doc/images/mediaplayerex.jpg delete mode 100644 doc/src/player.qdoc diff --git a/.gitignore b/.gitignore index 452e804..6efd255 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ CMakeCache.txt Makefile cmake_install.cmake player_autogen +Testing +CMakeCache.txt.prev +.cmake + diff --git a/doc/images/mediaplayerex.jpg b/doc/images/mediaplayerex.jpg deleted file mode 100644 index e875bd1340a90638dc86ea14abfaf0ef314aab09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28825 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 - \endcode - - and we can make widget 'volume' changes change the volume - - \code - connect(controls, SIGNAL(changeVolume(int)), player, SLOT(setVolume(int))); - \endcode - - The example also allows us to change video properties by means - of the QVideoWidget object. We can go to Full Screen mode with a single - button click, and back again. -*/ diff --git a/mediaplayer.cpp b/mediaplayer.cpp index e1a4d19..cc47cab 100644 --- a/mediaplayer.cpp +++ b/mediaplayer.cpp @@ -172,9 +172,7 @@ void MediaPlayer::stop(bool stopAudioOutput) return; if(stopAudioOutput) m_audioOutput->stop(); - // Clear buffers, avoids pops and clicks when playing after stopping - //m_audioOutput->reset(); - //this->reset(); + // Fully reset audio output clearAudioOutput(); setupAudioOutput(); @@ -306,11 +304,9 @@ void MediaPlayer::onAtEnd() void MediaPlayer::onOutputStateChanged(QAudio::State newState) { - qDebug() << "QAudioSink state change, new state:" << newState; - QAudio::Error error = m_audioOutput->error(); if(error != QAudio::NoError) { - qDebug() << "Audio Ouput error: " << error; + qDebug() << "Audio Ouput Error: " << error; } switch(newState) { @@ -319,7 +315,7 @@ void MediaPlayer::onOutputStateChanged(QAudio::State newState) if(this->bufferUnderrunRetries > MP_MAX_BUFFER_UNDERRUN_RETRIES) { this->stop(); - qDebug() << "Buffer underrun: max retries reached"; + qDebug() << "Media Player Buffer Underrun: max retries reached"; return; } this->bufferUnderrunRetries++; From 995674e0a18a27e157d25e53ae2217886995831b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Mon, 16 Sep 2024 00:09:16 -0600 Subject: [PATCH 06/16] cmake improvements --- CMakeLists.txt | 132 ++----------------------------------------------- 1 file changed, 4 insertions(+), 128 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ddfc72..1ca7a26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ project(player VERSION 1.0 LANGUAGES C CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOMOC ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core) @@ -38,7 +40,9 @@ qt_add_executable(player WIN32 MACOSX_BUNDLE systemaudiocontrol.cpp systemaudiocontrol.h titlebar.cpp titlebar.h titlebar.ui util.cpp util.h + uiassets.qrc ) + target_include_directories(player PRIVATE /usr/include/pipewire-0.3 /usr/include/python3.11 @@ -63,134 +67,6 @@ target_link_libraries(player PRIVATE tag ) - -# Resources: -set(uiassets_resource_files - "assets/LED_LCD_123.ttf" - "assets/Minecraft.ttf" - "assets/Winamp.ttf" - "assets/background.png" - "assets/balanceHandle.png" - "assets/balanceHandle_p.png" - "assets/bignumbers.ttf" - "assets/eq_off.png" - "assets/eq_off_p.png" - "assets/eq_on.png" - "assets/eq_on_p.png" - "assets/fb_folderIcon.png" - "assets/fb_folderIcon_selected.png" - "assets/fb_musicIcon.png" - "assets/fb_musicIcon_selected.png" - "assets/filesIcon.png" - "assets/logoButton.png" - "assets/next.png" - "assets/next_p.png" - "assets/open.png" - "assets/open_p.png" - "assets/pause.png" - "assets/pause_p.png" - "assets/pl_add.png" - "assets/pl_addIcon.png" - "assets/pl_add_p.png" - "assets/pl_close.png" - "assets/pl_close_p.png" - "assets/pl_homeIcon.png" - "assets/pl_off.png" - "assets/pl_off_p.png" - "assets/pl_on.png" - "assets/pl_on_p.png" - "assets/pl_playerIcon.png" - "assets/pl_upIcon.png" - "assets/play.png" - "assets/play_p.png" - "assets/playlistsIcon.png" - "assets/posHandle.png" - "assets/posHandle_p.png" - "assets/prev.png" - "assets/prev_p.png" - "assets/repeat_off.png" - "assets/repeat_off_p.png" - "assets/repeat_on.png" - "assets/repeat_on_p.png" - "assets/scroll_handle.png" - "assets/scroll_handle_p.png" - "assets/shuffle_off.png" - "assets/shuffle_off_p.png" - "assets/shuffle_on.png" - "assets/shuffle_on_p.png" - "assets/spotifyIcon.png" - "assets/status_paused.png" - "assets/status_playing.png" - "assets/status_stopped.png" - "assets/stop.png" - "assets/stop_p.png" - "assets/visualizationBackground.png" - "assets/volumeHandle.png" - "assets/volumeHandle_p.png" - "assets/windowClose.png" - "assets/windowMaximize.png" - "assets/windowMinimize.png" - "styles/controlbuttonswidget.repeatButton.1x.qss" - "styles/controlbuttonswidget.repeatButton.2x.qss" - "styles/controlbuttonswidget.repeatButton.3x.qss" - "styles/controlbuttonswidget.repeatButton.4x.qss" - "styles/controlbuttonswidget.shuffleButton.1x.qss" - "styles/controlbuttonswidget.shuffleButton.2x.qss" - "styles/controlbuttonswidget.shuffleButton.3x.qss" - "styles/controlbuttonswidget.shuffleButton.4x.qss" - "styles/desktopbasewindow.1x.qss" - "styles/desktopbasewindow.2x.qss" - "styles/desktopbasewindow.3x.qss" - "styles/desktopbasewindow.4x.qss" - "styles/playerview.balanceSlider.1x.qss" - "styles/playerview.balanceSlider.2x.qss" - "styles/playerview.balanceSlider.3x.qss" - "styles/playerview.balanceSlider.4x.qss" - "styles/playerview.codecDetailsContainer.1x.qss" - "styles/playerview.codecDetailsContainer.2x.qss" - "styles/playerview.codecDetailsContainer.3x.qss" - "styles/playerview.codecDetailsContainer.4x.qss" - "styles/playerview.eqButton.1x.qss" - "styles/playerview.eqButton.2x.qss" - "styles/playerview.eqButton.3x.qss" - "styles/playerview.eqButton.4x.qss" - "styles/playerview.kbpsFrame.1x.qss" - "styles/playerview.kbpsFrame.2x.qss" - "styles/playerview.kbpsFrame.3x.qss" - "styles/playerview.kbpsFrame.4x.qss" - "styles/playerview.khzFrame.1x.qss" - "styles/playerview.khzFrame.2x.qss" - "styles/playerview.khzFrame.3x.qss" - "styles/playerview.khzFrame.4x.qss" - "styles/playerview.playlistButton.1x.qss" - "styles/playerview.playlistButton.2x.qss" - "styles/playerview.playlistButton.3x.qss" - "styles/playerview.playlistButton.4x.qss" - "styles/playerview.posBar.1x.qss" - "styles/playerview.posBar.2x.qss" - "styles/playerview.posBar.3x.qss" - "styles/playerview.posBar.4x.qss" - "styles/playerview.songInfoContainer.1x.qss" - "styles/playerview.songInfoContainer.2x.qss" - "styles/playerview.songInfoContainer.3x.qss" - "styles/playerview.songInfoContainer.4x.qss" - "styles/playerview.visualizationFrame.1x.qss" - "styles/playerview.visualizationFrame.2x.qss" - "styles/playerview.visualizationFrame.3x.qss" - "styles/playerview.visualizationFrame.4x.qss" - "styles/playerview.volumeSlider.1x.qss" - "styles/playerview.volumeSlider.2x.qss" - "styles/playerview.volumeSlider.3x.qss" - "styles/playerview.volumeSlider.4x.qss" -) - -qt_add_resources(player "uiassets" - PREFIX - "/" - FILES - ${uiassets_resource_files} -) - install(TARGETS player BUNDLE DESTINATION . RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} From 4cf6a8abfc22b41691d8bfa4cc72f430a9587cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Mon, 16 Sep 2024 00:41:28 -0600 Subject: [PATCH 07/16] Initial refactor of directories --- CMakeLists.txt | 56 ++++++++++--------- audiosource.cpp => src/audiosource.cpp | 0 audiosource.h => src/audiosource.h | 0 .../audiosourcebluetooth.cpp | 0 .../audiosourcebluetooth.h | 0 audiosourcecd.cpp => src/audiosourcecd.cpp | 0 audiosourcecd.h => src/audiosourcecd.h | 0 .../audiosourcecoordinator.cpp | 0 .../audiosourcecoordinator.h | 0 .../audiosourcefile.cpp | 0 audiosourcefile.h => src/audiosourcefile.h | 0 .../audiosourcewspectrumcapture.cpp | 0 .../audiosourcewspectrumcapture.h | 0 .../controlbuttonswidget.cpp | 0 .../controlbuttonswidget.h | 0 .../controlbuttonswidget.ui | 0 .../desktopbasewindow.cpp | 0 .../desktopbasewindow.h | 0 .../desktopbasewindow.ui | 0 .../desktopplayerwindow.cpp | 0 .../desktopplayerwindow.h | 0 .../desktopplayerwindow.ui | 0 .../embeddedbasewindow.cpp | 0 .../embeddedbasewindow.h | 0 .../embeddedbasewindow.ui | 0 fft.cpp => src/fft.cpp | 0 fft.h => src/fft.h | 0 .../filebrowsericonprovider.cpp | 0 .../filebrowsericonprovider.h | 0 main.cpp => src/main.cpp | 0 mainmenuview.cpp => src/mainmenuview.cpp | 0 mainmenuview.h => src/mainmenuview.h | 0 mainmenuview.ui => src/mainmenuview.ui | 0 mainwindow.cpp => src/mainwindow.cpp | 0 mainwindow.h => src/mainwindow.h | 0 mediaplayer.cpp => src/mediaplayer.cpp | 0 mediaplayer.h => src/mediaplayer.h | 0 playerview.cpp => src/playerview.cpp | 0 playerview.h => src/playerview.h | 0 playerview.ui => src/playerview.ui | 0 playlistmodel.cpp => src/playlistmodel.cpp | 0 playlistmodel.h => src/playlistmodel.h | 0 playlistview.cpp => src/playlistview.cpp | 0 playlistview.h => src/playlistview.h | 0 playlistview.ui => src/playlistview.ui | 0 qmediaplaylist.cpp => src/qmediaplaylist.cpp | 0 qmediaplaylist.h => src/qmediaplaylist.h | 0 .../qmediaplaylist_p.cpp | 0 qmediaplaylist_p.h => src/qmediaplaylist_p.h | 0 .../qplaylistfileparser.cpp | 0 .../qplaylistfileparser.h | 0 scale.cpp => src/scale.cpp | 0 scale.h => src/scale.h | 0 scrolltext.cpp => src/scrolltext.cpp | 0 scrolltext.h => src/scrolltext.h | 0 spectrumwidget.cpp => src/spectrumwidget.cpp | 0 spectrumwidget.h => src/spectrumwidget.h | 0 .../systemaudiocontrol.cpp | 0 .../systemaudiocontrol.h | 0 titlebar.cpp => src/titlebar.cpp | 0 titlebar.h => src/titlebar.h | 0 titlebar.ui => src/titlebar.ui | 0 util.cpp => src/util.cpp | 0 util.h => src/util.h | 0 64 files changed, 29 insertions(+), 27 deletions(-) rename audiosource.cpp => src/audiosource.cpp (100%) rename audiosource.h => src/audiosource.h (100%) rename audiosourcebluetooth.cpp => src/audiosourcebluetooth.cpp (100%) rename audiosourcebluetooth.h => src/audiosourcebluetooth.h (100%) rename audiosourcecd.cpp => src/audiosourcecd.cpp (100%) rename audiosourcecd.h => src/audiosourcecd.h (100%) rename audiosourcecoordinator.cpp => src/audiosourcecoordinator.cpp (100%) rename audiosourcecoordinator.h => src/audiosourcecoordinator.h (100%) rename audiosourcefile.cpp => src/audiosourcefile.cpp (100%) rename audiosourcefile.h => src/audiosourcefile.h (100%) rename audiosourcewspectrumcapture.cpp => src/audiosourcewspectrumcapture.cpp (100%) rename audiosourcewspectrumcapture.h => src/audiosourcewspectrumcapture.h (100%) rename controlbuttonswidget.cpp => src/controlbuttonswidget.cpp (100%) rename controlbuttonswidget.h => src/controlbuttonswidget.h (100%) rename controlbuttonswidget.ui => src/controlbuttonswidget.ui (100%) rename desktopbasewindow.cpp => src/desktopbasewindow.cpp (100%) rename desktopbasewindow.h => src/desktopbasewindow.h (100%) rename desktopbasewindow.ui => src/desktopbasewindow.ui (100%) rename desktopplayerwindow.cpp => src/desktopplayerwindow.cpp (100%) rename desktopplayerwindow.h => src/desktopplayerwindow.h (100%) rename desktopplayerwindow.ui => src/desktopplayerwindow.ui (100%) rename embeddedbasewindow.cpp => src/embeddedbasewindow.cpp (100%) rename embeddedbasewindow.h => src/embeddedbasewindow.h (100%) rename embeddedbasewindow.ui => src/embeddedbasewindow.ui (100%) rename fft.cpp => src/fft.cpp (100%) rename fft.h => src/fft.h (100%) rename filebrowsericonprovider.cpp => src/filebrowsericonprovider.cpp (100%) rename filebrowsericonprovider.h => src/filebrowsericonprovider.h (100%) rename main.cpp => src/main.cpp (100%) rename mainmenuview.cpp => src/mainmenuview.cpp (100%) rename mainmenuview.h => src/mainmenuview.h (100%) rename mainmenuview.ui => src/mainmenuview.ui (100%) rename mainwindow.cpp => src/mainwindow.cpp (100%) rename mainwindow.h => src/mainwindow.h (100%) rename mediaplayer.cpp => src/mediaplayer.cpp (100%) rename mediaplayer.h => src/mediaplayer.h (100%) rename playerview.cpp => src/playerview.cpp (100%) rename playerview.h => src/playerview.h (100%) rename playerview.ui => src/playerview.ui (100%) rename playlistmodel.cpp => src/playlistmodel.cpp (100%) rename playlistmodel.h => src/playlistmodel.h (100%) rename playlistview.cpp => src/playlistview.cpp (100%) rename playlistview.h => src/playlistview.h (100%) rename playlistview.ui => src/playlistview.ui (100%) rename qmediaplaylist.cpp => src/qmediaplaylist.cpp (100%) rename qmediaplaylist.h => src/qmediaplaylist.h (100%) rename qmediaplaylist_p.cpp => src/qmediaplaylist_p.cpp (100%) rename qmediaplaylist_p.h => src/qmediaplaylist_p.h (100%) rename qplaylistfileparser.cpp => src/qplaylistfileparser.cpp (100%) rename qplaylistfileparser.h => src/qplaylistfileparser.h (100%) rename scale.cpp => src/scale.cpp (100%) rename scale.h => src/scale.h (100%) rename scrolltext.cpp => src/scrolltext.cpp (100%) rename scrolltext.h => src/scrolltext.h (100%) rename spectrumwidget.cpp => src/spectrumwidget.cpp (100%) rename spectrumwidget.h => src/spectrumwidget.h (100%) rename systemaudiocontrol.cpp => src/systemaudiocontrol.cpp (100%) rename systemaudiocontrol.h => src/systemaudiocontrol.h (100%) rename titlebar.cpp => src/titlebar.cpp (100%) rename titlebar.h => src/titlebar.h (100%) rename titlebar.ui => src/titlebar.ui (100%) rename util.cpp => src/util.cpp (100%) rename util.h => src/util.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ca7a26..ca98585 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,34 +12,36 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Concurrent DBus Gui Multi qt_standard_project_setup() +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) + qt_add_executable(player WIN32 MACOSX_BUNDLE - audiosource.cpp audiosource.h - audiosourcebluetooth.cpp audiosourcebluetooth.h - audiosourcecd.cpp audiosourcecd.h - audiosourcecoordinator.cpp audiosourcecoordinator.h - audiosourcefile.cpp audiosourcefile.h - audiosourcewspectrumcapture.cpp audiosourcewspectrumcapture.h - controlbuttonswidget.cpp controlbuttonswidget.h controlbuttonswidget.ui - desktopbasewindow.cpp desktopbasewindow.h desktopbasewindow.ui - desktopplayerwindow.cpp desktopplayerwindow.h desktopplayerwindow.ui - embeddedbasewindow.cpp embeddedbasewindow.h embeddedbasewindow.ui - fft.cpp fft.h - filebrowsericonprovider.cpp filebrowsericonprovider.h - main.cpp - mainmenuview.cpp mainmenuview.h mainmenuview.ui - mainwindow.cpp mainwindow.h - mediaplayer.cpp mediaplayer.h - playerview.cpp playerview.h playerview.ui - playlistmodel.cpp playlistmodel.h - playlistview.cpp playlistview.h playlistview.ui - qmediaplaylist.cpp qmediaplaylist.h qmediaplaylist_p.cpp qmediaplaylist_p.h - qplaylistfileparser.cpp qplaylistfileparser.h - scale.cpp scale.h - scrolltext.cpp scrolltext.h - spectrumwidget.cpp spectrumwidget.h - systemaudiocontrol.cpp systemaudiocontrol.h - titlebar.cpp titlebar.h titlebar.ui - util.cpp util.h + src/audiosource.cpp src/audiosource.h + src/audiosourcebluetooth.cpp src/audiosourcebluetooth.h + src/audiosourcecd.cpp src/audiosourcecd.h + src/audiosourcecoordinator.cpp src/audiosourcecoordinator.h + src/audiosourcefile.cpp src/audiosourcefile.h + src/audiosourcewspectrumcapture.cpp src/audiosourcewspectrumcapture.h + src/controlbuttonswidget.cpp src/controlbuttonswidget.h src/controlbuttonswidget.ui + src/desktopbasewindow.cpp src/desktopbasewindow.h src/desktopbasewindow.ui + src/desktopplayerwindow.cpp src/desktopplayerwindow.h src/desktopplayerwindow.ui + src/embeddedbasewindow.cpp src/embeddedbasewindow.h src/embeddedbasewindow.ui + src/fft.cpp src/fft.h + src/filebrowsericonprovider.cpp src/filebrowsericonprovider.h + src/main.cpp + src/mainmenuview.cpp src/mainmenuview.h src/mainmenuview.ui + src/mainwindow.cpp src/mainwindow.h + src/mediaplayer.cpp src/mediaplayer.h + src/playerview.cpp src/playerview.h src/playerview.ui + src/playlistmodel.cpp src/playlistmodel.h + src/playlistview.cpp src/playlistview.h src/playlistview.ui + src/qmediaplaylist.cpp src/qmediaplaylist.h src/qmediaplaylist_p.cpp src/qmediaplaylist_p.h + src/qplaylistfileparser.cpp src/qplaylistfileparser.h + src/scale.cpp src/scale.h + src/scrolltext.cpp src/scrolltext.h + src/spectrumwidget.cpp src/spectrumwidget.h + src/systemaudiocontrol.cpp src/systemaudiocontrol.h + src/titlebar.cpp src/titlebar.h src/titlebar.ui + src/util.cpp src/util.h uiassets.qrc ) diff --git a/audiosource.cpp b/src/audiosource.cpp similarity index 100% rename from audiosource.cpp rename to src/audiosource.cpp diff --git a/audiosource.h b/src/audiosource.h similarity index 100% rename from audiosource.h rename to src/audiosource.h diff --git a/audiosourcebluetooth.cpp b/src/audiosourcebluetooth.cpp similarity index 100% rename from audiosourcebluetooth.cpp rename to src/audiosourcebluetooth.cpp diff --git a/audiosourcebluetooth.h b/src/audiosourcebluetooth.h similarity index 100% rename from audiosourcebluetooth.h rename to src/audiosourcebluetooth.h diff --git a/audiosourcecd.cpp b/src/audiosourcecd.cpp similarity index 100% rename from audiosourcecd.cpp rename to src/audiosourcecd.cpp diff --git a/audiosourcecd.h b/src/audiosourcecd.h similarity index 100% rename from audiosourcecd.h rename to src/audiosourcecd.h diff --git a/audiosourcecoordinator.cpp b/src/audiosourcecoordinator.cpp similarity index 100% rename from audiosourcecoordinator.cpp rename to src/audiosourcecoordinator.cpp diff --git a/audiosourcecoordinator.h b/src/audiosourcecoordinator.h similarity index 100% rename from audiosourcecoordinator.h rename to src/audiosourcecoordinator.h diff --git a/audiosourcefile.cpp b/src/audiosourcefile.cpp similarity index 100% rename from audiosourcefile.cpp rename to src/audiosourcefile.cpp diff --git a/audiosourcefile.h b/src/audiosourcefile.h similarity index 100% rename from audiosourcefile.h rename to src/audiosourcefile.h diff --git a/audiosourcewspectrumcapture.cpp b/src/audiosourcewspectrumcapture.cpp similarity index 100% rename from audiosourcewspectrumcapture.cpp rename to src/audiosourcewspectrumcapture.cpp diff --git a/audiosourcewspectrumcapture.h b/src/audiosourcewspectrumcapture.h similarity index 100% rename from audiosourcewspectrumcapture.h rename to src/audiosourcewspectrumcapture.h diff --git a/controlbuttonswidget.cpp b/src/controlbuttonswidget.cpp similarity index 100% rename from controlbuttonswidget.cpp rename to src/controlbuttonswidget.cpp diff --git a/controlbuttonswidget.h b/src/controlbuttonswidget.h similarity index 100% rename from controlbuttonswidget.h rename to src/controlbuttonswidget.h diff --git a/controlbuttonswidget.ui b/src/controlbuttonswidget.ui similarity index 100% rename from controlbuttonswidget.ui rename to src/controlbuttonswidget.ui diff --git a/desktopbasewindow.cpp b/src/desktopbasewindow.cpp similarity index 100% rename from desktopbasewindow.cpp rename to src/desktopbasewindow.cpp diff --git a/desktopbasewindow.h b/src/desktopbasewindow.h similarity index 100% rename from desktopbasewindow.h rename to src/desktopbasewindow.h diff --git a/desktopbasewindow.ui b/src/desktopbasewindow.ui similarity index 100% rename from desktopbasewindow.ui rename to src/desktopbasewindow.ui diff --git a/desktopplayerwindow.cpp b/src/desktopplayerwindow.cpp similarity index 100% rename from desktopplayerwindow.cpp rename to src/desktopplayerwindow.cpp diff --git a/desktopplayerwindow.h b/src/desktopplayerwindow.h similarity index 100% rename from desktopplayerwindow.h rename to src/desktopplayerwindow.h diff --git a/desktopplayerwindow.ui b/src/desktopplayerwindow.ui similarity index 100% rename from desktopplayerwindow.ui rename to src/desktopplayerwindow.ui diff --git a/embeddedbasewindow.cpp b/src/embeddedbasewindow.cpp similarity index 100% rename from embeddedbasewindow.cpp rename to src/embeddedbasewindow.cpp diff --git a/embeddedbasewindow.h b/src/embeddedbasewindow.h similarity index 100% rename from embeddedbasewindow.h rename to src/embeddedbasewindow.h diff --git a/embeddedbasewindow.ui b/src/embeddedbasewindow.ui similarity index 100% rename from embeddedbasewindow.ui rename to src/embeddedbasewindow.ui diff --git a/fft.cpp b/src/fft.cpp similarity index 100% rename from fft.cpp rename to src/fft.cpp diff --git a/fft.h b/src/fft.h similarity index 100% rename from fft.h rename to src/fft.h diff --git a/filebrowsericonprovider.cpp b/src/filebrowsericonprovider.cpp similarity index 100% rename from filebrowsericonprovider.cpp rename to src/filebrowsericonprovider.cpp diff --git a/filebrowsericonprovider.h b/src/filebrowsericonprovider.h similarity index 100% rename from filebrowsericonprovider.h rename to src/filebrowsericonprovider.h diff --git a/main.cpp b/src/main.cpp similarity index 100% rename from main.cpp rename to src/main.cpp diff --git a/mainmenuview.cpp b/src/mainmenuview.cpp similarity index 100% rename from mainmenuview.cpp rename to src/mainmenuview.cpp diff --git a/mainmenuview.h b/src/mainmenuview.h similarity index 100% rename from mainmenuview.h rename to src/mainmenuview.h diff --git a/mainmenuview.ui b/src/mainmenuview.ui similarity index 100% rename from mainmenuview.ui rename to src/mainmenuview.ui diff --git a/mainwindow.cpp b/src/mainwindow.cpp similarity index 100% rename from mainwindow.cpp rename to src/mainwindow.cpp diff --git a/mainwindow.h b/src/mainwindow.h similarity index 100% rename from mainwindow.h rename to src/mainwindow.h diff --git a/mediaplayer.cpp b/src/mediaplayer.cpp similarity index 100% rename from mediaplayer.cpp rename to src/mediaplayer.cpp diff --git a/mediaplayer.h b/src/mediaplayer.h similarity index 100% rename from mediaplayer.h rename to src/mediaplayer.h diff --git a/playerview.cpp b/src/playerview.cpp similarity index 100% rename from playerview.cpp rename to src/playerview.cpp diff --git a/playerview.h b/src/playerview.h similarity index 100% rename from playerview.h rename to src/playerview.h diff --git a/playerview.ui b/src/playerview.ui similarity index 100% rename from playerview.ui rename to src/playerview.ui diff --git a/playlistmodel.cpp b/src/playlistmodel.cpp similarity index 100% rename from playlistmodel.cpp rename to src/playlistmodel.cpp diff --git a/playlistmodel.h b/src/playlistmodel.h similarity index 100% rename from playlistmodel.h rename to src/playlistmodel.h diff --git a/playlistview.cpp b/src/playlistview.cpp similarity index 100% rename from playlistview.cpp rename to src/playlistview.cpp diff --git a/playlistview.h b/src/playlistview.h similarity index 100% rename from playlistview.h rename to src/playlistview.h diff --git a/playlistview.ui b/src/playlistview.ui similarity index 100% rename from playlistview.ui rename to src/playlistview.ui diff --git a/qmediaplaylist.cpp b/src/qmediaplaylist.cpp similarity index 100% rename from qmediaplaylist.cpp rename to src/qmediaplaylist.cpp diff --git a/qmediaplaylist.h b/src/qmediaplaylist.h similarity index 100% rename from qmediaplaylist.h rename to src/qmediaplaylist.h diff --git a/qmediaplaylist_p.cpp b/src/qmediaplaylist_p.cpp similarity index 100% rename from qmediaplaylist_p.cpp rename to src/qmediaplaylist_p.cpp diff --git a/qmediaplaylist_p.h b/src/qmediaplaylist_p.h similarity index 100% rename from qmediaplaylist_p.h rename to src/qmediaplaylist_p.h diff --git a/qplaylistfileparser.cpp b/src/qplaylistfileparser.cpp similarity index 100% rename from qplaylistfileparser.cpp rename to src/qplaylistfileparser.cpp diff --git a/qplaylistfileparser.h b/src/qplaylistfileparser.h similarity index 100% rename from qplaylistfileparser.h rename to src/qplaylistfileparser.h diff --git a/scale.cpp b/src/scale.cpp similarity index 100% rename from scale.cpp rename to src/scale.cpp diff --git a/scale.h b/src/scale.h similarity index 100% rename from scale.h rename to src/scale.h diff --git a/scrolltext.cpp b/src/scrolltext.cpp similarity index 100% rename from scrolltext.cpp rename to src/scrolltext.cpp diff --git a/scrolltext.h b/src/scrolltext.h similarity index 100% rename from scrolltext.h rename to src/scrolltext.h diff --git a/spectrumwidget.cpp b/src/spectrumwidget.cpp similarity index 100% rename from spectrumwidget.cpp rename to src/spectrumwidget.cpp diff --git a/spectrumwidget.h b/src/spectrumwidget.h similarity index 100% rename from spectrumwidget.h rename to src/spectrumwidget.h diff --git a/systemaudiocontrol.cpp b/src/systemaudiocontrol.cpp similarity index 100% rename from systemaudiocontrol.cpp rename to src/systemaudiocontrol.cpp diff --git a/systemaudiocontrol.h b/src/systemaudiocontrol.h similarity index 100% rename from systemaudiocontrol.h rename to src/systemaudiocontrol.h diff --git a/titlebar.cpp b/src/titlebar.cpp similarity index 100% rename from titlebar.cpp rename to src/titlebar.cpp diff --git a/titlebar.h b/src/titlebar.h similarity index 100% rename from titlebar.h rename to src/titlebar.h diff --git a/titlebar.ui b/src/titlebar.ui similarity index 100% rename from titlebar.ui rename to src/titlebar.ui diff --git a/util.cpp b/src/util.cpp similarity index 100% rename from util.cpp rename to src/util.cpp diff --git a/util.h b/src/util.h similarity index 100% rename from util.h rename to src/util.h From 08ad2c2f8a66f2e2480b25d2a536f3c190c00bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Mon, 16 Sep 2024 01:26:13 -0600 Subject: [PATCH 08/16] New folder structure --- CMakeLists.txt | 98 ++++++++++++++----- src/{ => audiosource-base}/audiosource.cpp | 0 src/{ => audiosource-base}/audiosource.h | 0 .../audiosourcewspectrumcapture.cpp | 0 .../audiosourcewspectrumcapture.h | 0 .../audiosourcecoordinator.cpp | 0 .../audiosourcecoordinator.h | 0 .../audiosourcebluetooth.cpp | 0 .../audiosourcebluetooth.h | 0 src/{ => audiosourcecd}/audiosourcecd.cpp | 0 src/{ => audiosourcecd}/audiosourcecd.h | 0 src/{ => audiosourcefile}/audiosourcefile.cpp | 0 src/{ => audiosourcefile}/audiosourcefile.h | 0 src/{ => audiosourcefile}/mediaplayer.cpp | 0 src/{ => audiosourcefile}/mediaplayer.h | 0 src/{ => shared}/fft.cpp | 0 src/{ => shared}/fft.h | 0 src/{ => shared}/scale.cpp | 0 src/{ => shared}/scale.h | 0 src/{ => shared}/systemaudiocontrol.cpp | 0 src/{ => shared}/systemaudiocontrol.h | 0 src/{ => shared}/util.cpp | 0 src/{ => shared}/util.h | 0 .../desktopbasewindow.cpp | 0 src/{ => view-basewindow}/desktopbasewindow.h | 0 .../desktopbasewindow.ui | 0 .../desktopplayerwindow.cpp | 0 .../desktopplayerwindow.h | 0 .../desktopplayerwindow.ui | 0 .../embeddedbasewindow.cpp | 0 .../embeddedbasewindow.h | 0 .../embeddedbasewindow.ui | 0 src/{ => view-basewindow}/mainwindow.cpp | 0 src/{ => view-basewindow}/mainwindow.h | 0 src/{ => view-basewindow}/titlebar.cpp | 0 src/{ => view-basewindow}/titlebar.h | 0 src/{ => view-basewindow}/titlebar.ui | 0 src/{ => view-menu}/mainmenuview.cpp | 0 src/{ => view-menu}/mainmenuview.h | 0 src/{ => view-menu}/mainmenuview.ui | 0 .../controlbuttonswidget.cpp | 0 src/{ => view-player}/controlbuttonswidget.h | 0 src/{ => view-player}/controlbuttonswidget.ui | 0 src/{ => view-player}/playerview.cpp | 0 src/{ => view-player}/playerview.h | 0 src/{ => view-player}/playerview.ui | 0 src/{ => view-player}/scrolltext.cpp | 0 src/{ => view-player}/scrolltext.h | 0 src/{ => view-player}/spectrumwidget.cpp | 0 src/{ => view-player}/spectrumwidget.h | 0 .../filebrowsericonprovider.cpp | 0 .../filebrowsericonprovider.h | 0 src/{ => view-playlist}/playlistmodel.cpp | 0 src/{ => view-playlist}/playlistmodel.h | 0 src/{ => view-playlist}/playlistview.cpp | 0 src/{ => view-playlist}/playlistview.h | 0 src/{ => view-playlist}/playlistview.ui | 0 src/{ => view-playlist}/qmediaplaylist.cpp | 0 src/{ => view-playlist}/qmediaplaylist.h | 0 src/{ => view-playlist}/qmediaplaylist_p.cpp | 0 src/{ => view-playlist}/qmediaplaylist_p.h | 0 .../qplaylistfileparser.cpp | 0 src/{ => view-playlist}/qplaylistfileparser.h | 0 63 files changed, 72 insertions(+), 26 deletions(-) rename src/{ => audiosource-base}/audiosource.cpp (100%) rename src/{ => audiosource-base}/audiosource.h (100%) rename src/{ => audiosource-base}/audiosourcewspectrumcapture.cpp (100%) rename src/{ => audiosource-base}/audiosourcewspectrumcapture.h (100%) rename src/{ => audiosource-coordinator}/audiosourcecoordinator.cpp (100%) rename src/{ => audiosource-coordinator}/audiosourcecoordinator.h (100%) rename src/{ => audiosourcebluetooth}/audiosourcebluetooth.cpp (100%) rename src/{ => audiosourcebluetooth}/audiosourcebluetooth.h (100%) rename src/{ => audiosourcecd}/audiosourcecd.cpp (100%) rename src/{ => audiosourcecd}/audiosourcecd.h (100%) rename src/{ => audiosourcefile}/audiosourcefile.cpp (100%) rename src/{ => audiosourcefile}/audiosourcefile.h (100%) rename src/{ => audiosourcefile}/mediaplayer.cpp (100%) rename src/{ => audiosourcefile}/mediaplayer.h (100%) rename src/{ => shared}/fft.cpp (100%) rename src/{ => shared}/fft.h (100%) rename src/{ => shared}/scale.cpp (100%) rename src/{ => shared}/scale.h (100%) rename src/{ => shared}/systemaudiocontrol.cpp (100%) rename src/{ => shared}/systemaudiocontrol.h (100%) rename src/{ => shared}/util.cpp (100%) rename src/{ => shared}/util.h (100%) rename src/{ => view-basewindow}/desktopbasewindow.cpp (100%) rename src/{ => view-basewindow}/desktopbasewindow.h (100%) rename src/{ => view-basewindow}/desktopbasewindow.ui (100%) rename src/{ => view-basewindow}/desktopplayerwindow.cpp (100%) rename src/{ => view-basewindow}/desktopplayerwindow.h (100%) rename src/{ => view-basewindow}/desktopplayerwindow.ui (100%) rename src/{ => view-basewindow}/embeddedbasewindow.cpp (100%) rename src/{ => view-basewindow}/embeddedbasewindow.h (100%) rename src/{ => view-basewindow}/embeddedbasewindow.ui (100%) rename src/{ => view-basewindow}/mainwindow.cpp (100%) rename src/{ => view-basewindow}/mainwindow.h (100%) rename src/{ => view-basewindow}/titlebar.cpp (100%) rename src/{ => view-basewindow}/titlebar.h (100%) rename src/{ => view-basewindow}/titlebar.ui (100%) rename src/{ => view-menu}/mainmenuview.cpp (100%) rename src/{ => view-menu}/mainmenuview.h (100%) rename src/{ => view-menu}/mainmenuview.ui (100%) rename src/{ => view-player}/controlbuttonswidget.cpp (100%) rename src/{ => view-player}/controlbuttonswidget.h (100%) rename src/{ => view-player}/controlbuttonswidget.ui (100%) rename src/{ => view-player}/playerview.cpp (100%) rename src/{ => view-player}/playerview.h (100%) rename src/{ => view-player}/playerview.ui (100%) rename src/{ => view-player}/scrolltext.cpp (100%) rename src/{ => view-player}/scrolltext.h (100%) rename src/{ => view-player}/spectrumwidget.cpp (100%) rename src/{ => view-player}/spectrumwidget.h (100%) rename src/{ => view-playlist}/filebrowsericonprovider.cpp (100%) rename src/{ => view-playlist}/filebrowsericonprovider.h (100%) rename src/{ => view-playlist}/playlistmodel.cpp (100%) rename src/{ => view-playlist}/playlistmodel.h (100%) rename src/{ => view-playlist}/playlistview.cpp (100%) rename src/{ => view-playlist}/playlistview.h (100%) rename src/{ => view-playlist}/playlistview.ui (100%) rename src/{ => view-playlist}/qmediaplaylist.cpp (100%) rename src/{ => view-playlist}/qmediaplaylist.h (100%) rename src/{ => view-playlist}/qmediaplaylist_p.cpp (100%) rename src/{ => view-playlist}/qmediaplaylist_p.h (100%) rename src/{ => view-playlist}/qplaylistfileparser.cpp (100%) rename src/{ => view-playlist}/qplaylistfileparser.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca98585..33eee7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,35 +13,81 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Concurrent DBus Gui Multi qt_standard_project_setup() include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/audiosource-base) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/audiosource-coordinator) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/audiosourcebluetooth) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/audiosourcecd) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/audiosourcefile) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/shared) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/view-basewindow) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/view-menu) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/view-player) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/view-playlist) qt_add_executable(player WIN32 MACOSX_BUNDLE - src/audiosource.cpp src/audiosource.h - src/audiosourcebluetooth.cpp src/audiosourcebluetooth.h - src/audiosourcecd.cpp src/audiosourcecd.h - src/audiosourcecoordinator.cpp src/audiosourcecoordinator.h - src/audiosourcefile.cpp src/audiosourcefile.h - src/audiosourcewspectrumcapture.cpp src/audiosourcewspectrumcapture.h - src/controlbuttonswidget.cpp src/controlbuttonswidget.h src/controlbuttonswidget.ui - src/desktopbasewindow.cpp src/desktopbasewindow.h src/desktopbasewindow.ui - src/desktopplayerwindow.cpp src/desktopplayerwindow.h src/desktopplayerwindow.ui - src/embeddedbasewindow.cpp src/embeddedbasewindow.h src/embeddedbasewindow.ui - src/fft.cpp src/fft.h - src/filebrowsericonprovider.cpp src/filebrowsericonprovider.h + src/audiosource-base/audiosource.cpp + src/audiosource-base/audiosource.h + src/audiosource-base/audiosourcewspectrumcapture.cpp + src/audiosource-base/audiosourcewspectrumcapture.h + src/audiosourcebluetooth/audiosourcebluetooth.cpp + src/audiosourcebluetooth/audiosourcebluetooth.h + src/audiosourcecd/audiosourcecd.cpp + src/audiosourcecd/audiosourcecd.h + src/audiosource-coordinator/audiosourcecoordinator.cpp + src/audiosource-coordinator/audiosourcecoordinator.h + src/audiosourcefile/audiosourcefile.cpp + src/audiosourcefile/audiosourcefile.h + src/audiosourcefile/mediaplayer.cpp + src/audiosourcefile/mediaplayer.h + src/view-player/controlbuttonswidget.cpp + src/view-player/controlbuttonswidget.h + src/view-player/controlbuttonswidget.ui + src/view-player/scrolltext.cpp + src/view-player/scrolltext.h + src/view-player/spectrumwidget.cpp + src/view-player/spectrumwidget.h + src/view-player/playerview.cpp + src/view-player/playerview.h + src/view-player/playerview.ui + src/view-basewindow/desktopbasewindow.cpp + src/view-basewindow/desktopbasewindow.h + src/view-basewindow/desktopbasewindow.ui + src/view-basewindow/desktopplayerwindow.cpp + src/view-basewindow/desktopplayerwindow.h + src/view-basewindow/desktopplayerwindow.ui + src/view-basewindow/embeddedbasewindow.cpp + src/view-basewindow/embeddedbasewindow.h + src/view-basewindow/embeddedbasewindow.ui + src/view-basewindow/mainwindow.cpp + src/view-basewindow/mainwindow.h + src/view-basewindow/titlebar.cpp + src/view-basewindow/titlebar.h + src/view-basewindow/titlebar.ui + src/view-playlist/filebrowsericonprovider.cpp + src/view-playlist/filebrowsericonprovider.h + src/view-playlist/playlistmodel.cpp + src/view-playlist/playlistmodel.h + src/view-playlist/playlistview.cpp + src/view-playlist/playlistview.h + src/view-playlist/playlistview.ui + src/view-playlist/qmediaplaylist.cpp + src/view-playlist/qmediaplaylist.h + src/view-playlist/qmediaplaylist_p.cpp + src/view-playlist/qmediaplaylist_p.h + src/view-playlist/qplaylistfileparser.cpp + src/view-playlist/qplaylistfileparser.h + src/view-menu/mainmenuview.cpp + src/view-menu/mainmenuview.h + src/view-menu/mainmenuview.ui + src/shared/scale.cpp + src/shared/scale.h + src/shared/systemaudiocontrol.cpp + src/shared/systemaudiocontrol.h + src/shared/fft.cpp + src/shared/fft.h + src/shared/util.cpp + src/shared/util.h src/main.cpp - src/mainmenuview.cpp src/mainmenuview.h src/mainmenuview.ui - src/mainwindow.cpp src/mainwindow.h - src/mediaplayer.cpp src/mediaplayer.h - src/playerview.cpp src/playerview.h src/playerview.ui - src/playlistmodel.cpp src/playlistmodel.h - src/playlistview.cpp src/playlistview.h src/playlistview.ui - src/qmediaplaylist.cpp src/qmediaplaylist.h src/qmediaplaylist_p.cpp src/qmediaplaylist_p.h - src/qplaylistfileparser.cpp src/qplaylistfileparser.h - src/scale.cpp src/scale.h - src/scrolltext.cpp src/scrolltext.h - src/spectrumwidget.cpp src/spectrumwidget.h - src/systemaudiocontrol.cpp src/systemaudiocontrol.h - src/titlebar.cpp src/titlebar.h src/titlebar.ui - src/util.cpp src/util.h uiassets.qrc ) diff --git a/src/audiosource.cpp b/src/audiosource-base/audiosource.cpp similarity index 100% rename from src/audiosource.cpp rename to src/audiosource-base/audiosource.cpp diff --git a/src/audiosource.h b/src/audiosource-base/audiosource.h similarity index 100% rename from src/audiosource.h rename to src/audiosource-base/audiosource.h diff --git a/src/audiosourcewspectrumcapture.cpp b/src/audiosource-base/audiosourcewspectrumcapture.cpp similarity index 100% rename from src/audiosourcewspectrumcapture.cpp rename to src/audiosource-base/audiosourcewspectrumcapture.cpp diff --git a/src/audiosourcewspectrumcapture.h b/src/audiosource-base/audiosourcewspectrumcapture.h similarity index 100% rename from src/audiosourcewspectrumcapture.h rename to src/audiosource-base/audiosourcewspectrumcapture.h diff --git a/src/audiosourcecoordinator.cpp b/src/audiosource-coordinator/audiosourcecoordinator.cpp similarity index 100% rename from src/audiosourcecoordinator.cpp rename to src/audiosource-coordinator/audiosourcecoordinator.cpp diff --git a/src/audiosourcecoordinator.h b/src/audiosource-coordinator/audiosourcecoordinator.h similarity index 100% rename from src/audiosourcecoordinator.h rename to src/audiosource-coordinator/audiosourcecoordinator.h diff --git a/src/audiosourcebluetooth.cpp b/src/audiosourcebluetooth/audiosourcebluetooth.cpp similarity index 100% rename from src/audiosourcebluetooth.cpp rename to src/audiosourcebluetooth/audiosourcebluetooth.cpp diff --git a/src/audiosourcebluetooth.h b/src/audiosourcebluetooth/audiosourcebluetooth.h similarity index 100% rename from src/audiosourcebluetooth.h rename to src/audiosourcebluetooth/audiosourcebluetooth.h diff --git a/src/audiosourcecd.cpp b/src/audiosourcecd/audiosourcecd.cpp similarity index 100% rename from src/audiosourcecd.cpp rename to src/audiosourcecd/audiosourcecd.cpp diff --git a/src/audiosourcecd.h b/src/audiosourcecd/audiosourcecd.h similarity index 100% rename from src/audiosourcecd.h rename to src/audiosourcecd/audiosourcecd.h diff --git a/src/audiosourcefile.cpp b/src/audiosourcefile/audiosourcefile.cpp similarity index 100% rename from src/audiosourcefile.cpp rename to src/audiosourcefile/audiosourcefile.cpp diff --git a/src/audiosourcefile.h b/src/audiosourcefile/audiosourcefile.h similarity index 100% rename from src/audiosourcefile.h rename to src/audiosourcefile/audiosourcefile.h diff --git a/src/mediaplayer.cpp b/src/audiosourcefile/mediaplayer.cpp similarity index 100% rename from src/mediaplayer.cpp rename to src/audiosourcefile/mediaplayer.cpp diff --git a/src/mediaplayer.h b/src/audiosourcefile/mediaplayer.h similarity index 100% rename from src/mediaplayer.h rename to src/audiosourcefile/mediaplayer.h diff --git a/src/fft.cpp b/src/shared/fft.cpp similarity index 100% rename from src/fft.cpp rename to src/shared/fft.cpp diff --git a/src/fft.h b/src/shared/fft.h similarity index 100% rename from src/fft.h rename to src/shared/fft.h diff --git a/src/scale.cpp b/src/shared/scale.cpp similarity index 100% rename from src/scale.cpp rename to src/shared/scale.cpp diff --git a/src/scale.h b/src/shared/scale.h similarity index 100% rename from src/scale.h rename to src/shared/scale.h diff --git a/src/systemaudiocontrol.cpp b/src/shared/systemaudiocontrol.cpp similarity index 100% rename from src/systemaudiocontrol.cpp rename to src/shared/systemaudiocontrol.cpp diff --git a/src/systemaudiocontrol.h b/src/shared/systemaudiocontrol.h similarity index 100% rename from src/systemaudiocontrol.h rename to src/shared/systemaudiocontrol.h diff --git a/src/util.cpp b/src/shared/util.cpp similarity index 100% rename from src/util.cpp rename to src/shared/util.cpp diff --git a/src/util.h b/src/shared/util.h similarity index 100% rename from src/util.h rename to src/shared/util.h diff --git a/src/desktopbasewindow.cpp b/src/view-basewindow/desktopbasewindow.cpp similarity index 100% rename from src/desktopbasewindow.cpp rename to src/view-basewindow/desktopbasewindow.cpp diff --git a/src/desktopbasewindow.h b/src/view-basewindow/desktopbasewindow.h similarity index 100% rename from src/desktopbasewindow.h rename to src/view-basewindow/desktopbasewindow.h diff --git a/src/desktopbasewindow.ui b/src/view-basewindow/desktopbasewindow.ui similarity index 100% rename from src/desktopbasewindow.ui rename to src/view-basewindow/desktopbasewindow.ui diff --git a/src/desktopplayerwindow.cpp b/src/view-basewindow/desktopplayerwindow.cpp similarity index 100% rename from src/desktopplayerwindow.cpp rename to src/view-basewindow/desktopplayerwindow.cpp diff --git a/src/desktopplayerwindow.h b/src/view-basewindow/desktopplayerwindow.h similarity index 100% rename from src/desktopplayerwindow.h rename to src/view-basewindow/desktopplayerwindow.h diff --git a/src/desktopplayerwindow.ui b/src/view-basewindow/desktopplayerwindow.ui similarity index 100% rename from src/desktopplayerwindow.ui rename to src/view-basewindow/desktopplayerwindow.ui diff --git a/src/embeddedbasewindow.cpp b/src/view-basewindow/embeddedbasewindow.cpp similarity index 100% rename from src/embeddedbasewindow.cpp rename to src/view-basewindow/embeddedbasewindow.cpp diff --git a/src/embeddedbasewindow.h b/src/view-basewindow/embeddedbasewindow.h similarity index 100% rename from src/embeddedbasewindow.h rename to src/view-basewindow/embeddedbasewindow.h diff --git a/src/embeddedbasewindow.ui b/src/view-basewindow/embeddedbasewindow.ui similarity index 100% rename from src/embeddedbasewindow.ui rename to src/view-basewindow/embeddedbasewindow.ui diff --git a/src/mainwindow.cpp b/src/view-basewindow/mainwindow.cpp similarity index 100% rename from src/mainwindow.cpp rename to src/view-basewindow/mainwindow.cpp diff --git a/src/mainwindow.h b/src/view-basewindow/mainwindow.h similarity index 100% rename from src/mainwindow.h rename to src/view-basewindow/mainwindow.h diff --git a/src/titlebar.cpp b/src/view-basewindow/titlebar.cpp similarity index 100% rename from src/titlebar.cpp rename to src/view-basewindow/titlebar.cpp diff --git a/src/titlebar.h b/src/view-basewindow/titlebar.h similarity index 100% rename from src/titlebar.h rename to src/view-basewindow/titlebar.h diff --git a/src/titlebar.ui b/src/view-basewindow/titlebar.ui similarity index 100% rename from src/titlebar.ui rename to src/view-basewindow/titlebar.ui diff --git a/src/mainmenuview.cpp b/src/view-menu/mainmenuview.cpp similarity index 100% rename from src/mainmenuview.cpp rename to src/view-menu/mainmenuview.cpp diff --git a/src/mainmenuview.h b/src/view-menu/mainmenuview.h similarity index 100% rename from src/mainmenuview.h rename to src/view-menu/mainmenuview.h diff --git a/src/mainmenuview.ui b/src/view-menu/mainmenuview.ui similarity index 100% rename from src/mainmenuview.ui rename to src/view-menu/mainmenuview.ui diff --git a/src/controlbuttonswidget.cpp b/src/view-player/controlbuttonswidget.cpp similarity index 100% rename from src/controlbuttonswidget.cpp rename to src/view-player/controlbuttonswidget.cpp diff --git a/src/controlbuttonswidget.h b/src/view-player/controlbuttonswidget.h similarity index 100% rename from src/controlbuttonswidget.h rename to src/view-player/controlbuttonswidget.h diff --git a/src/controlbuttonswidget.ui b/src/view-player/controlbuttonswidget.ui similarity index 100% rename from src/controlbuttonswidget.ui rename to src/view-player/controlbuttonswidget.ui diff --git a/src/playerview.cpp b/src/view-player/playerview.cpp similarity index 100% rename from src/playerview.cpp rename to src/view-player/playerview.cpp diff --git a/src/playerview.h b/src/view-player/playerview.h similarity index 100% rename from src/playerview.h rename to src/view-player/playerview.h diff --git a/src/playerview.ui b/src/view-player/playerview.ui similarity index 100% rename from src/playerview.ui rename to src/view-player/playerview.ui diff --git a/src/scrolltext.cpp b/src/view-player/scrolltext.cpp similarity index 100% rename from src/scrolltext.cpp rename to src/view-player/scrolltext.cpp diff --git a/src/scrolltext.h b/src/view-player/scrolltext.h similarity index 100% rename from src/scrolltext.h rename to src/view-player/scrolltext.h diff --git a/src/spectrumwidget.cpp b/src/view-player/spectrumwidget.cpp similarity index 100% rename from src/spectrumwidget.cpp rename to src/view-player/spectrumwidget.cpp diff --git a/src/spectrumwidget.h b/src/view-player/spectrumwidget.h similarity index 100% rename from src/spectrumwidget.h rename to src/view-player/spectrumwidget.h diff --git a/src/filebrowsericonprovider.cpp b/src/view-playlist/filebrowsericonprovider.cpp similarity index 100% rename from src/filebrowsericonprovider.cpp rename to src/view-playlist/filebrowsericonprovider.cpp diff --git a/src/filebrowsericonprovider.h b/src/view-playlist/filebrowsericonprovider.h similarity index 100% rename from src/filebrowsericonprovider.h rename to src/view-playlist/filebrowsericonprovider.h diff --git a/src/playlistmodel.cpp b/src/view-playlist/playlistmodel.cpp similarity index 100% rename from src/playlistmodel.cpp rename to src/view-playlist/playlistmodel.cpp diff --git a/src/playlistmodel.h b/src/view-playlist/playlistmodel.h similarity index 100% rename from src/playlistmodel.h rename to src/view-playlist/playlistmodel.h diff --git a/src/playlistview.cpp b/src/view-playlist/playlistview.cpp similarity index 100% rename from src/playlistview.cpp rename to src/view-playlist/playlistview.cpp diff --git a/src/playlistview.h b/src/view-playlist/playlistview.h similarity index 100% rename from src/playlistview.h rename to src/view-playlist/playlistview.h diff --git a/src/playlistview.ui b/src/view-playlist/playlistview.ui similarity index 100% rename from src/playlistview.ui rename to src/view-playlist/playlistview.ui diff --git a/src/qmediaplaylist.cpp b/src/view-playlist/qmediaplaylist.cpp similarity index 100% rename from src/qmediaplaylist.cpp rename to src/view-playlist/qmediaplaylist.cpp diff --git a/src/qmediaplaylist.h b/src/view-playlist/qmediaplaylist.h similarity index 100% rename from src/qmediaplaylist.h rename to src/view-playlist/qmediaplaylist.h diff --git a/src/qmediaplaylist_p.cpp b/src/view-playlist/qmediaplaylist_p.cpp similarity index 100% rename from src/qmediaplaylist_p.cpp rename to src/view-playlist/qmediaplaylist_p.cpp diff --git a/src/qmediaplaylist_p.h b/src/view-playlist/qmediaplaylist_p.h similarity index 100% rename from src/qmediaplaylist_p.h rename to src/view-playlist/qmediaplaylist_p.h diff --git a/src/qplaylistfileparser.cpp b/src/view-playlist/qplaylistfileparser.cpp similarity index 100% rename from src/qplaylistfileparser.cpp rename to src/view-playlist/qplaylistfileparser.cpp diff --git a/src/qplaylistfileparser.h b/src/view-playlist/qplaylistfileparser.h similarity index 100% rename from src/qplaylistfileparser.h rename to src/view-playlist/qplaylistfileparser.h From b68f9c8655548e1d2ef61c4db325854561de4921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Mon, 16 Sep 2024 01:36:41 -0600 Subject: [PATCH 09/16] Further cleanup --- assets/LED_LCD_123.ttf | Bin 47608 -> 0 bytes assets/Minecraft.ttf | Bin 14488 -> 0 bytes assets/Winamp.ttf | Bin 45388 -> 0 bytes assets/background.png | Bin 20829 -> 0 bytes skin/background.png | Bin 12735 -> 0 bytes uiassets.qrc | 4 ---- 6 files changed, 4 deletions(-) delete mode 100644 assets/LED_LCD_123.ttf delete mode 100644 assets/Minecraft.ttf delete mode 100644 assets/Winamp.ttf delete mode 100644 assets/background.png delete mode 100644 skin/background.png diff --git a/assets/LED_LCD_123.ttf b/assets/LED_LCD_123.ttf deleted file mode 100644 index 8d6588cc5205fd3371b915ff637165e0c2c4348e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47608 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 Z*c*kN@$GAW{e3oGeYSI$CI24pe*xM150(G` diff --git a/assets/Winamp.ttf b/assets/Winamp.ttf deleted file mode 100644 index d90aa698f32cc660bbddfd08e142146c6c2140c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45388 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 WEWn@M{;_F+@QA-Z#~uj`g#Q6Yr=o8F diff --git a/assets/background.png b/assets/background.png deleted file mode 100644 index 34d359c4b896a59540cbfd09cf4746398b69212b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20829 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 diff --git a/skin/background.png b/skin/background.png deleted file mode 100644 index faf27e96a1852084737f6379c4e961bdfce704f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12735 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 FV1l(QZTkQK diff --git a/uiassets.qrc b/uiassets.qrc index 6a8f181..da106bd 100644 --- a/uiassets.qrc +++ b/uiassets.qrc @@ -12,7 +12,6 @@ assets/prev.png assets/stop_p.png assets/stop.png - assets/background.png assets/posHandle_p.png assets/posHandle.png assets/eq_off_p.png @@ -35,10 +34,7 @@ assets/balanceHandle.png assets/volumeHandle_p.png assets/volumeHandle.png - assets/Minecraft.ttf - assets/Winamp.ttf assets/visualizationBackground.png - assets/LED_LCD_123.ttf assets/status_paused.png assets/status_stopped.png assets/status_playing.png From eefe3438c101abcc660cab2f52b4f69599a4b3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Tue, 17 Sep 2024 17:09:27 -0600 Subject: [PATCH 10/16] More cleanup, restore buffer clearing on stop --- player.pro | 100 ---------------------------- src/audiosourcefile/mediaplayer.cpp | 2 + 2 files changed, 2 insertions(+), 100 deletions(-) delete mode 100644 player.pro diff --git a/player.pro b/player.pro deleted file mode 100644 index a695fa0..0000000 --- a/player.pro +++ /dev/null @@ -1,100 +0,0 @@ -TEMPLATE = app -TARGET = player - -QT += network \ - multimedia \ - multimediawidgets \ - widgets \ - concurrent \ - dbus - -LIBS += -ltag -lasound -lpulse -lpulse-simple -lpipewire-0.3 -L/usr/lib/python3.11/config-3.11-x86_64-linux-gnu/ -lpython3.11 -INCLUDEPATH += /usr/include/python3.11 /usr/include/pipewire-0.3 /usr/include/spa-0.2 - -HEADERS = \ - audiosource.h \ - audiosourcebluetooth.h \ - audiosourcecd.h \ - audiosourcecoordinator.h \ - audiosourcefile.h \ - audiosourcewspectrumcapture.h \ - controlbuttonswidget.h \ - desktopbasewindow.h \ - desktopplayerwindow.h \ - embeddedbasewindow.h \ - fft.h \ - filebrowsericonprovider.h \ - mainmenuview.h \ - mainwindow.h \ - mediaplayer.h \ - playerview.h \ - playlistmodel.h \ - playlistview.h \ - scale.h \ - scrolltext.h \ - qmediaplaylist.h \ - qmediaplaylist_p.h \ - qplaylistfileparser.h \ - spectrumwidget.h \ - systemaudiocontrol.h \ - titlebar.h \ - util.h - -SOURCES = main.cpp \ - audiosource.cpp \ - audiosourcebluetooth.cpp \ - audiosourcecd.cpp \ - audiosourcecoordinator.cpp \ - audiosourcefile.cpp \ - audiosourcewspectrumcapture.cpp \ - controlbuttonswidget.cpp \ - desktopbasewindow.cpp \ - desktopplayerwindow.cpp \ - embeddedbasewindow.cpp \ - fft.cpp \ - filebrowsericonprovider.cpp \ - mainmenuview.cpp \ - mainwindow.cpp \ - mediaplayer.cpp \ - playerview.cpp \ - playlistmodel.cpp \ - playlistview.cpp \ - scale.cpp \ - scrolltext.cpp \ - qmediaplaylist.cpp \ - qmediaplaylist_p.cpp \ - qplaylistfileparser.cpp \ - spectrumwidget.cpp \ - systemaudiocontrol.cpp \ - titlebar.cpp \ - util.cpp - -target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/player -INSTALLS += target - -FORMS += \ - controlbuttonswidget.ui \ - desktopbasewindow.ui \ - desktopplayerwindow.ui \ - embeddedbasewindow.ui \ - mainmenuview.ui \ - playerview.ui \ - playlistview.ui \ - titlebar.ui - -RESOURCES += \ - uiassets.qrc - -DISTFILES += \ - README.md \ - install.sh \ - python/linamp/__init__.py \ - python/linamp/cdplayer.py \ - python/linamp-mock/__init__.py \ - python/linamp-mock/mock_cdplayer.py \ - python/requirements.txt \ - scale-skin.sh \ - setup.sh \ - shutdown.sh \ - start.sh \ - styles/controlbuttonswidget.shuffleButton.4x.qss diff --git a/src/audiosourcefile/mediaplayer.cpp b/src/audiosourcefile/mediaplayer.cpp index cc47cab..71ca158 100644 --- a/src/audiosourcefile/mediaplayer.cpp +++ b/src/audiosourcefile/mediaplayer.cpp @@ -172,6 +172,8 @@ void MediaPlayer::stop(bool stopAudioOutput) return; if(stopAudioOutput) m_audioOutput->stop(); + // Clear buffers, avoids pops and clicks when playing after stopping + this->reset(); // Fully reset audio output clearAudioOutput(); setupAudioOutput(); From e0065835ca72d4b29dc0a7a91d77470aa2789d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Tue, 17 Sep 2024 21:55:56 -0600 Subject: [PATCH 11/16] Update changelog and version --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0a2ade7..985221c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +linamp (1.2.0) bookworm; urgency=medium + + * Bugfix: After boot and loading the first file into the playlist, playback fails. + * Bugfix: Fix issue caused by playing and sopping the same file repeatedly (it glitched and refused to play). + * Refactor: new folder structure for better code maintainability. + + -- Rodrigo Méndez Tue, 17 Sep 2024 21:54:00 -0600 + linamp (1.1.2) bookworm; urgency=medium * Trim trailing whitespace. From fed2765ef843fcef0b11c36dac17d91eeef00338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Wed, 4 Dec 2024 16:39:37 -0600 Subject: [PATCH 12/16] Fix stereo on spectrum analyzer --- src/view-player/spectrumwidget.cpp | 23 +++++++++++++++++------ src/view-player/spectrumwidget.h | 2 +- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/view-player/spectrumwidget.cpp b/src/view-player/spectrumwidget.cpp index 11c90ff..8a5029d 100644 --- a/src/view-player/spectrumwidget.cpp +++ b/src/view-player/spectrumwidget.cpp @@ -19,11 +19,11 @@ float pcmToFloat(qint16 pcm) static void floatPcmToMono(const float *data, float *mono, int channels) { if (channels == 1) { - memcpy(mono, data, sizeof(float) * 512); + memcpy(mono, data, sizeof(float) * N); } else { float *set = mono; - while (set < &mono[512]) { + while (set < &mono[N]) { *set++ = (data[0] + data[1]) / 2; data += channels; } @@ -185,7 +185,7 @@ void SpectrumWidget::paintEvent (QPaintEvent *) if(m_playing) { float mono[N]; float freq[N / 2]; - int channels = 2; // TODO get from format + int channels = m_format.channelCount(); floatPcmToMono(m_data, mono, channels); calc_freq(mono, freq); @@ -225,20 +225,31 @@ void SpectrumWidget::setData(const QByteArray &data, QAudioFormat format) m_format = format; Q_ASSERT(m_format.sampleFormat() == QAudioFormat::Int16); + if(m_format.sampleFormat() != QAudioFormat::Int16) { + // Bad sample format, only Int16 is currently supported + return; + } + const int bytesPerFrame = format.bytesPerFrame(); + Q_ASSERT(bytesPerFrame == 4); // Expecting Stereo Int16 + + if(bytesPerFrame != 4) { + // Bad bytes per frame, expecting 4 (Int16 Stereo) + return; + } - if(data.length() < DFT_SIZE * 4) { + if(data.length() < DFT_SIZE * bytesPerFrame) { // Not enough data for processing, ignore return; } const char *ptr = data.constData(); - for (int i = 0; i < DFT_SIZE * 2; ++i) { + for (int i = 0; i < DFT_SIZE * bytesPerFrame; ++i) { const qint16 pcmSample = *reinterpret_cast(ptr); // Scale down to range [-1.0, 1.0] float floatSample = pcmToFloat(pcmSample); m_data[i] = floatSample; - ptr += bytesPerFrame; + ptr += 2; } } diff --git a/src/view-player/spectrumwidget.h b/src/view-player/spectrumwidget.h index f8d2062..41d234a 100644 --- a/src/view-player/spectrumwidget.h +++ b/src/view-player/spectrumwidget.h @@ -21,7 +21,7 @@ class SpectrumWidget : public QWidget void paintEvent (QPaintEvent *); private: - float m_data[DFT_SIZE * 2]; + float m_data[DFT_SIZE * 4]; float m_xscale[N_BANDS + 1]; int m_bandValues[N_BANDS + 1]; int m_bandDelays[N_BANDS + 1]; From 27bfc42cb1aea3d23c378996dc4b00f37e94e91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Wed, 4 Dec 2024 23:19:45 -0600 Subject: [PATCH 13/16] Fix glitches on spectrum when using audiosourcespectrumcapture --- src/audiosource-base/audiosourcewspectrumcapture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audiosource-base/audiosourcewspectrumcapture.cpp b/src/audiosource-base/audiosourcewspectrumcapture.cpp index b689f99..04897aa 100644 --- a/src/audiosource-base/audiosourcewspectrumcapture.cpp +++ b/src/audiosource-base/audiosourcewspectrumcapture.cpp @@ -204,7 +204,7 @@ void AudioSourceWSpectrumCapture::pwLoop() &pwData); struct spa_audio_info_raw audio_info; - audio_info.format = SPA_AUDIO_FORMAT_S16_LE; + audio_info.format = SPA_AUDIO_FORMAT_S16P; audio_info.channels = SPECTRUM_DATA_CHANNELS; audio_info.rate = SPECTRUM_DATA_SAMPLE_RATE; params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, From e7701923275732c08235e6d4bf1282eee0ec70b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Tue, 10 Dec 2024 22:08:03 -0600 Subject: [PATCH 14/16] Fix crashes on CD player when request to musicbrainz fails --- python/linamp/cdplayer.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/python/linamp/cdplayer.py b/python/linamp/cdplayer.py index 969563a..4c25797 100644 --- a/python/linamp/cdplayer.py +++ b/python/linamp/cdplayer.py @@ -75,7 +75,7 @@ def fetchdata(): result = musicbrainzngs.get_releases_by_discid( disc.id, includes=["artists", "recordings"] ) # get data from Musicbrainz - except musicbrainzngs.ResponseError: + except Exception: print( "disc not found or bad response, using cdtxt instead" ) # if not available search for cdtext @@ -148,6 +148,15 @@ def fetchdata(): artists[t - i_first_track] = value pass d.close() + + # artists and track_list should be arrays of strings, make sure they are: + for i, artist in enumerate(artists): + if type(artist) is not str: + artists[i] = "Unknown" + for i, track in enumerate(track_list): + if type(track) is not str: + track_list[i] = f"Track {i + 1}" + return artists, track_list, album, i_tracks, durations, is_data_tracks From 17111c55116f622eb33e929848772c4e933764f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Tue, 10 Dec 2024 23:19:28 -0600 Subject: [PATCH 15/16] Fix issues with audiosourcewspectrumcapture, removed function that is no longer needed after previous fix --- .../audiosourcewspectrumcapture.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/audiosource-base/audiosourcewspectrumcapture.cpp b/src/audiosource-base/audiosourcewspectrumcapture.cpp index 04897aa..08257ba 100644 --- a/src/audiosource-base/audiosourcewspectrumcapture.cpp +++ b/src/audiosource-base/audiosourcewspectrumcapture.cpp @@ -8,17 +8,6 @@ bool globalAudioSourceWSpectrumCaptureInstanceIsRunning = false; -bool is_valid_sample(QByteArray *sample) -{ - // Greedy: suposing that 100 is enough - for(int i = 0; i < 100; i++) { - if(sample->at(i) != 0) { - return true; - } - } - return false; -} - /* our data processing function is in general: * * struct pw_buffer *b; @@ -238,10 +227,6 @@ void AudioSourceWSpectrumCapture::emitData() return; } - if(!is_valid_sample(pwData.sample)) { - return; - } - emit dataEmitted(*pwData.sample, spectrumDataFormat); pwData.sample->clear(); delete pwData.sampleStream; From dbe3c3bfedc84d2d17d012bf87356a96a10e1c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20M=C3=A9ndez?= Date: Tue, 10 Dec 2024 23:27:20 -0600 Subject: [PATCH 16/16] Update changelog and version --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index 985221c..cbda2f9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +linamp (1.2.1) bookworm; urgency=medium + + * Bugfix: Fixed glitches on spectrum analyzer for views that use audiospectrumcatpure class (CD player, Bluetooth player) + * Bugfix: Fixed spectrum analyzer not showing spectrum of right channel on file player + * Bugfix: Fix crashes on CD player when a request to musicbrainz fails + + -- Rodrigo Méndez Tue, 10 Dec 2024 23:22:00 -0600 + linamp (1.2.0) bookworm; urgency=medium * Bugfix: After boot and loading the first file into the playlist, playback fails.