diff options
56 files changed, 503 insertions, 185 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..6a5ddc910e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,202 @@ +name: Build + +on: + push: + pull_request: + +env: + CMAKEFLAGS_COMMON: -DCMAKE_BUILD_TYPE=Release -DBATTERY=ON -DBROADCAST=ON -DBULK=ON -DDEBUG_ASSERTIONS_FATAL=ON -DHID=ON -DLILV=ON -DOPUS=ON -DQTKEYCHAIN=ON -DVINYLCONTROL=ON + GTEST_COLOR: 1 + CTEST_OUTPUT_ON_FAILURE: 1 + # Render analyzer waveform tests to an offscreen buffer + QT_QPA_PLATFORM: offscreen + # GitHub Actions automatically zstd compresses caches + CCACHE_NOCOMPRESS: true + +jobs: + build-ubuntu-gcc: + name: Ubuntu 18.04 (gcc) + runs-on: ubuntu-18.04 + steps: + - name: Check out repository + uses: actions/checkout@v2 + - name: Install build dependencies + run: | + sudo apt-get update && sudo apt-get install -y --no-install-recommends \ + ccache \ + libavformat-dev \ + libchromaprint-dev \ + libebur128-dev \ + libfaad-dev \ + libfftw3-dev \ + libflac-dev \ + libid3tag0-dev \ + liblilv-dev \ + libmad0-dev \ + libmodplug-dev \ + libmp3lame-dev \ + libmp4v2-dev \ + libopus-dev \ + libopusfile-dev \ + libportmidi-dev \ + libprotobuf-dev \ + libqt5opengl5-dev \ + libqt5sql5-sqlite \ + libqt5svg5-dev \ + libqt5x11extras5-dev \ + librubberband-dev \ + libshout3-dev \ + libsndfile1-dev \ + libsoundtouch-dev \ + libsqlite3-dev \ + libtag1-dev \ + libupower-glib-dev \ + libusb-1.0-0-dev \ + libwavpack-dev \ + portaudio19-dev \ + protobuf-compiler \ + qt5-default \ + qt5keychain-dev \ + qtscript5-dev \ + - name: Set up cmake + uses: jwlawson/actions-setup-cmake@v1.4 + with: + # This should always match the mininum required version in + # our CMakeLists.txt + cmake-version: '3.13.x' + - name: Create build directory + run: mkdir cmake_build + - name: Set up ccache cache + uses: actions/cache@v2 + with: + path: ~/.ccache + key: ${{ runner.os }}-ccache-${{ github.head_ref }}-${{ github.run_number }} + restore-keys: | + ${{ runner.os }}-ccache-${{ github.head_ref }} + ${{ runner.os }}-ccache + - name: Configure + run: cmake $CMAKE_FLAGS_COMMON $CMAKE_FLAGS_UBUNTU -S . -B cmake_build + env: + # TODO for Ubuntu Focal: Replace "-DFAAD=ON" with "-DFFMPEG=ON" + CMAKE_FLAGS_UBUNTU: -DFAAD=ON -DKEYFINDER=ON -DLOCALECOMPARE=ON -DMAD=ON -DMODPLUG=ON -DWAVPACK=ON + - name: Set up problem matcher + uses: ammaraskar/gcc-problem-matcher@master + - name: Build + run: cmake --build . -j $(nproc) + working-directory: cmake_build + - name: Test + run: ctest --timeout 45 + working-directory: cmake_build + - name: Package + run: cpack -G DEB + working-directory: cmake_build + - name: Deploy artifacts + uses: actions/upload-artifact@v2 + with: + name: Ubuntu DEB + path: cmake_build/*.deb + + build-mac: + name: macOS 10.15 + runs-on: macos-10.15 + env: + APPLE_CODESIGN_IDENTITY: 2C2B5D3EDCE82BA55E22E9A67F16F8D03E390870 + steps: + - name: clone Git repository + uses: actions/checkout@v2 + - name: ccache + uses: actions/cache@v2 + env: + cache-name: ccache + with: + path: /Users/runner/Library/Caches/ccache + key: ${{ runner.os }}-ccache-${{ github.head_ref }}-${{ github.run_number }} + restore-keys: | + ${{ runner.os }}-ccache-${{ github.head_ref }} + ${{ runner.os }}-ccache + - name: read build environment file + id: read_build_environment_file + run: | + read -r MIXXX_ENVNAME < cmake/macos_build_environment_name + echo "::set-output name=buildenv_name::$MIXXX_ENVNAME" + - name: macOS build environment cache + uses: actions/cache@v2 + env: + cache-name: macOS build environment + with: + path: /Users/runner/buildenv + key: macOS-build-environment-${{ steps.read_build_environment_file.outputs.buildenv_name }} + - name: import code signing identity + env: + MACOS_CODESIGN_OPENSSL_PASSWORD: ${{ secrets.MACOS_CODESIGN_OPENSSL_PASSWORD }} + MACOS_CODESIGN_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CODESIGN_CERTIFICATE_PASSWORD }} + run: | + if [ -n "$MACOS_CODESIGN_OPENSSL_PASSWORD" ] && [ -n "$MACOS_CODESIGN_CERTIFICATE_PASSWORD" ]; then + # Decrypt the certificate + openssl enc -aes-256-cbc -d -md sha512 \ + -k ${MACOS_CODESIGN_OPENSSL_PASSWORD} \ + -in /Users/runner/work/mixxx/mixxx/cmake/macos_developer_id_codesign_certificate.p12.enc \ + -out ~/certificate.p12 + + # Create a temporary keychain for the certificate and import it. + security create-keychain -p mixxx Mixxx.keychain + security unlock-keychain -p mixxx Mixxx.keychain + security import ~/certificate.p12 -k Mixxx.keychain \ + -P ${MACOS_CODESIGN_CERTIFICATE_PASSWORD} -T /usr/bin/codesign + security set-key-partition-list -S apple-tool:,apple: -k mixxx Mixxx.keychain + # Add keychain to search list + security list-keychains -s Mixxx.keychain + fi + - name: build + run: | + if [[ $MIXXX_ENVNAME =~ .*macosminimum([0-9]*\.[0-9]*).* ]]; then + export MACOSX_DEPLOYMENT_TARGET=${BASH_REMATCH[1]} + else + echo "Build environment did not match expected pattern. Check cmake/macos_build_environment_name file." + exit + fi + + mkdir -p /Users/runner/buildenv + export MIXXX_ENVPATH="/Users/runner/buildenv/$MIXXX_ENVNAME" + if [ ! -d "$MIXXX_ENVPATH" ]; then + # TODO: download from downloads.mixxx.org + curl "http://beasintheverb.me/${MIXXX_ENVNAME}.tar.gz" -o /Users/runner/buildenv/${MIXXX_ENVNAME}.tar.gz + tar xf /Users/runner/buildenv/${MIXXX_ENVNAME}.tar.gz -C /Users/runner/buildenv + rm /Users/runner/buildenv/${MIXXX_ENVNAME}.tar.gz + fi + export QT_DIR="$(find "${MIXXX_ENVPATH}" -type d -path "*/cmake/Qt5")" + export QT_QPA_PLATFORM_PLUGIN_PATH="$(find "${MIXXX_ENVPATH}" -type d -path "*/plugins")" + + export PATH="${MIXXX_ENVPATH}/bin:$PATH" + ccache -M 5G + + if [ -n "$MACOS_CODESIGN_OPENSSL_PASSWORD" ] && [ -n "$MACOS_CODESIGN_CERTIFICATE_PASSWORD" ]; then + export CMAKE_FLAGS_MAC="$CMAKE_FLAGS_MAC -DAPPLE_CODESIGN_IDENTITY=${APPLE_CODESIGN_IDENTITY}" + fi + + cd /Users/runner/work/mixxx/mixxx + mkdir cmake_build + cd cmake_build + cmake -L $CMAKEFLAGS $CMAKEFLAGS_MACOS -DCMAKE_PREFIX_PATH=${MIXXX_ENVPATH} -DQt5_DIR=${QT_DIR} .. + cmake --build . --parallel $(sysctl -n hw.physicalcpu) + cmake --build . --target benchmark + #TODO: fix disabled test + ctest --timeout 45 --exclude-regex DirectoryDAOTest.relocateDirectory + ccache -s + env: + CMAKEFLAGS_MACOS: -DCOREAUDIO=ON -DHSS1394=ON -DMACOS_BUNDLE=ON + MIXXX_ENVNAME: ${{ steps.read_build_environment_file.outputs.buildenv_name }} + - name: package app bundle + working-directory: cmake_build + run: | + cpack -G DragNDrop + if [ -n "$MACOS_CODESIGN_OPENSSL_PASSWORD" ] && [ -n "$MACOS_CODESIGN_CERTIFICATE_PASSWORD" ]; then + codesign --verbose=4 --deep --force --options runtime \ + --sign $APPLE_CODESIGN_IDENTITY \ + --entitlements ../build/osx/entitlements.plist *.dmg + fi + - name: upload macOS DMG artifact + uses: actions/upload-artifact@v2 + with: + name: macOS-DMG + path: cmake_build/*.dmg diff --git a/CMakeLists.txt b/CMakeLists.txt index ba83ab9a94..674226cb6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,10 @@ else() set(LLVM_CLANG false) endif() +if(APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.14) + add_compile_options(-fno-aligned-allocation) +endif() + # CMake implicitly sets the variable MSVC to true for Microsoft # Visual C++ or another compiler simulating Visual C++. # https://cmake.org/cmake/help/latest/variable/MSVC.html @@ -1085,7 +1089,6 @@ if (APPLE) set(MACOS_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION}") set(MACOS_BUNDLE_SHORTVERSION "${CMAKE_PROJECT_VERSION}") - set(MACOS_BUNDLE_MINOSVERSION "10.12.0") set_target_properties(mixxx PROPERTIES MACOSX_BUNDLE true diff --git a/cmake/macos_build_environment_name b/cmake/macos_build_environment_name new file mode 100644 index 0000000000..561d1f9c3a --- /dev/null +++ b/cmake/macos_build_environment_name @@ -0,0 +1 @@ +2.3-1db6c06-sdk10.15-macosminimum10.12-x86_64 diff --git a/cmake/macos_bundle.plist.in b/cmake/macos_bundle.plist.in index 1f8af6bb1e..472b7554af 100644 --- a/cmake/macos_bundle.plist.in +++ b/cmake/macos_bundle.plist.in @@ -36,6 +36,6 @@ <string>public.app-category.music</string> <key>LSMinimumSystemVersion</key> - <string>@MACOS_BUNDLE_MINVERSION@</string> + <string>@CMAKE_OSX_DEPLOYMENT_TARGET@</string> </dict> </plist> diff --git a/res/controllers/midi-components-0.0.js b/res/controllers/midi-components-0.0.js index 086ef96bf9..37f223f382 100644 --- a/res/controllers/midi-components-0.0.js +++ b/res/controllers/midi-components-0.0.js @@ -748,6 +748,8 @@ this.setCurrentUnit = function(newNumber) { this.currentUnitNumber = newNumber; + this.group = "[EffectRack1_EffectUnit" + newNumber + "]"; + if (allowFocusWhenParametersHidden) { engine.setValue(this.group, "show_focus", 0); } else { @@ -758,8 +760,6 @@ } engine.setValue(this.group, "controller_input_active", 0); - this.group = "[EffectRack1_EffectUnit" + newNumber + "]"; - if (allowFocusWhenParametersHidden) { engine.setValue(this.group, "show_focus", 1); } else { @@ -867,6 +867,7 @@ }; this.EffectUnitKnob.prototype = new Pot({ group: this.group, + number: this.currentUnitNumber, unshift: function() { this.input = function(channel, control, value, _status, _group) { if (this.MSB !== undefined) { diff --git a/src/controllers/controllerlearningeventfilter.cpp b/src/controllers/controllerlearningeventfilter.cpp index 8ed901fc2e..bdf96d5472 100644 --- a/src/controllers/controllerlearningeventfilter.cpp +++ b/src/controllers/controllerlearningeventfilter.cpp @@ -19,14 +19,14 @@ ControllerLearningEventFilter::~ControllerLearningEventFilter() { bool ControllerLearningEventFilter::eventFilter(QObject* pObject, QEvent* pEvent) { //qDebug() << "ControllerLearningEventFilter::eventFilter" << pObject << pEvent; - WWidget* pWidget = dynamic_cast<WWidget*>(pObject); + WWidget* pWidget = qobject_cast<WWidget*>(pObject); if (!pWidget || !m_bListening) { return false; } - WKnob* pKnob = dynamic_cast<WKnob*>(pObject); - WKnobComposed* pKnobComposed = dynamic_cast<WKnobComposed*>(pObject); - WSliderComposed* pSlider = dynamic_cast<WSliderComposed*>(pObject); + WKnob* pKnob = qobject_cast<WKnob*>(pObject); + WKnobComposed* pKnobComposed = qobject_cast<WKnobComposed*>(pObject); + WSliderComposed* pSlider = qobject_cast<WSliderComposed*>(pObject); bool has_right_click_reset = pKnob || pKnobComposed || pSlider; if (pEvent->type() == QEvent::KeyPress) { diff --git a/src/controllers/delegates/controldelegate.cpp b/src/controllers/delegates/controldelegate.cpp index cfae30ac79..6c6a330060 100644 --- a/src/controllers/delegates/controldelegate.cpp +++ b/src/controllers/delegates/controldelegate.cpp @@ -63,7 +63,7 @@ void ControlDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { ConfigKey key = index.data(Qt::EditRole).value<ConfigKey>(); - QLineEdit* pLineEdit = dynamic_cast<QLineEdit*>(editor); + QLineEdit* pLineEdit = qobject_cast<QLineEdit*>(editor); if (pLineEdit == NULL) { return; } diff --git a/src/controllers/delegates/midibytedelegate.cpp b/src/controllers/delegates/midibytedelegate.cpp index 50314deba3..8739c66029 100644 --- a/src/controllers/delegates/midibytedelegate.cpp +++ b/src/controllers/delegates/midibytedelegate.cpp @@ -30,7 +30,7 @@ QString MidiByteDelegate::displayText(const QVariant& value, void MidiByteDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { int control = index.data(Qt::EditRole).toInt(); - HexSpinBox* pSpinBox = dynamic_cast<HexSpinBox*>(editor); + HexSpinBox* pSpinBox = qobject_cast<HexSpinBox*>(editor); if (pSpinBox == NULL) { return; } @@ -40,7 +40,7 @@ void MidiByteDelegate::setEditorData(QWidget* editor, void MidiByteDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { - HexSpinBox* pSpinBox = dynamic_cast<HexSpinBox*>(editor); + HexSpinBox* pSpinBox = qobject_cast<HexSpinBox*>(editor); if (pSpinBox == NULL) { return; } diff --git a/src/controllers/delegates/midichanneldelegate.cpp b/src/controllers/delegates/midichanneldelegate.cpp index 6602025d83..831e336d26 100644 --- a/src/controllers/delegates/midichanneldelegate.cpp +++ b/src/controllers/delegates/midichanneldelegate.cpp @@ -34,7 +34,7 @@ QString MidiChannelDelegate::displayText(const QVariant& value, void MidiChannelDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { int channel = index.data(Qt::EditRole).toInt(); - QSpinBox* pSpinBox = dynamic_cast<QSpinBox*>(editor); + QSpinBox* pSpinBox = qobject_cast<QSpinBox*>(editor); if (pSpinBox == NULL) { return; } @@ -45,7 +45,7 @@ void MidiChannelDelegate::setEditorData(QWidget* editor, void MidiChannelDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { - QSpinBox* pSpinBox = dynamic_cast<QSpinBox*>(editor); + QSpinBox* pSpinBox = qobject_cast<QSpinBox*>(editor); if (pSpinBox == NULL) { return; } diff --git a/src/controllers/delegates/midiopcodedelegate.cpp b/src/controllers/delegates/midiopcodedelegate.cpp index b4cb9e4aad..21cd363966 100644 --- a/src/controllers/delegates/midiopcodedelegate.cpp +++ b/src/controllers/delegates/midiopcodedelegate.cpp @@ -40,7 +40,7 @@ QString MidiOpCodeDelegate::displayText(const QVariant& value, void MidiOpCodeDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { int opCode = index.data(Qt::EditRole).toInt(); - QComboBox* pComboBox = dynamic_cast<QComboBox*>(editor); + QComboBox* pComboBox = qobject_cast<QComboBox*>(editor); if (pComboBox == NULL) { return; } @@ -55,7 +55,7 @@ void MidiOpCodeDelegate::setEditorData(QWidget* editor, void MidiOpCodeDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { - QComboBox* pComboBox = dynamic_cast<QComboBox*>(editor); + QComboBox* pComboBox = qobject_cast<QComboBox*>(editor); if (pComboBox == NULL) { return; } diff --git a/src/controllers/delegates/midioptionsdelegate.cpp b/src/controllers/delegates/midioptionsdelegate.cpp index 3674bae528..3b6e45db52 100644 --- a/src/controllers/delegates/midioptionsdelegate.cpp +++ b/src/controllers/delegates/midioptionsdelegate.cpp @@ -66,7 +66,7 @@ void MidiOptionsDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { MidiOptions options = index.data(Qt::EditRole).value<MidiOptions>(); - QComboBox* pComboBox = dynamic_cast<QComboBox*>(editor); + QComboBox* pComboBox = qobject_cast<QComboBox*>(editor); if (pComboBox == NULL) { return; } diff --git a/src/controllers/softtakeover.cpp b/src/controllers/softtakeover.cpp index f304f357e3..eea05b5691 100644 --- a/src/controllers/softtakeover.cpp +++ b/src/controllers/softtakeover.cpp @@ -32,7 +32,7 @@ SoftTakeoverCtrl::~SoftTakeoverCtrl() { } void SoftTakeoverCtrl::enable(ControlObject* control) { - ControlPotmeter* cpo = dynamic_cast<ControlPotmeter*>(control); + ControlPotmeter* cpo = qobject_cast<ControlPotmeter*>(control); if (cpo == NULL) { // softtakecover works only for continuous ControlPotmeter based COs return; diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp index b8546e887f..ea2924cca0 100644 --- a/src/library/autodj/dlgautodj.cpp +++ b/src/library/autodj/dlgautodj.cpp @@ -66,7 +66,7 @@ DlgAutoDJ::DlgAutoDJ(WLibrary* parent, m_pTrackTableView, &WTrackTableView::setSelectedClick); - QBoxLayout* box = dynamic_cast<QBoxLayout*>(layout()); + QBoxLayout* box = qobject_cast<QBoxLayout*>(layout()); VERIFY_OR_DEBUG_ASSERT(box) { //Assumes the form layout is a QVBox/QHBoxLayout! } else { box->removeWidget(m_pTrackTablePlaceholder); diff --git a/src/library/coverartdelegate.cpp b/src/library/coverartdelegate.cpp index 9beec05333..1d56880958 100644 --- a/src/library/coverartdelegate.cpp +++ b/src/library/coverartdelegate.cpp @@ -118,7 +118,7 @@ void CoverArtDelegate::paintItem( return; } const double scaleFactor = - getDevicePixelRatioF(static_cast<QWidget*>(parent())); + getDevicePixelRatioF(qobject_cast<QWidget*>(parent())); QPixmap pixmap = m_pCache->tryLoadCover(this, coverInfo, static_cast<int>(option.rect.width() * scaleFactor), diff --git a/src/library/dlganalysis.cpp b/src/library/dlganalysis.cpp index 50077f30ae..94abf4efa5 100644 --- a/src/library/dlganalysis.cpp +++ b/src/library/dlganalysis.cpp @@ -40,7 +40,7 @@ DlgAnalysis::DlgAnalysis(WLibrary* parent, this, &DlgAnalysis::trackSelected); - QBoxLayout* box = dynamic_cast<QBoxLayout*>(layout()); + QBoxLayout* box = qobject_cast<QBoxLayout*>(layout()); VERIFY_OR_DEBUG_ASSERT(box) { // Assumes the form layout is a QVBox/QHBoxLayout! } else { box->removeWidget(m_pTrackTablePlaceholder); diff --git a/src/library/dlghidden.cpp b/src/library/dlghidden.cpp index 63cb6deac3..d06f2105f3 100644 --- a/src/library/dlghidden.cpp +++ b/src/library/dlghidden.cpp @@ -24,7 +24,7 @@ DlgHidden::DlgHidden( m_pTrackTableView->installEventFilter(pKeyboard); // Install our own trackTable - QBoxLayout* box = dynamic_cast<QBoxLayout*>(layout()); + QBoxLayout* box = qobject_cast<QBoxLayout*>(layout()); VERIFY_OR_DEBUG_ASSERT(box) { //Assumes the form layout is a QVBox/QHBoxLayout! } else { box->removeWidget(m_pTrackTablePlaceholder); diff --git a/src/library/dlgmissing.cpp b/src/library/dlgmissing.cpp index c73d6e3ec4..a6255e31c5 100644 --- a/src/library/dlgmissing.cpp +++ b/src/library/dlgmissing.cpp @@ -24,7 +24,7 @@ DlgMissing::DlgMissing( m_pTrackTableView->installEventFilter(pKeyboard); // Install our own trackTable - QBoxLayout* box = dynamic_cast<QBoxLayout*>(layout()); + QBoxLayout* box = qobject_cast<QBoxLayout*>(layout()); VERIFY_OR_DEBUG_ASSERT(box) { //Assumes the form layout is a QVBox/QHBoxLayout! } else { box->removeWidget(m_pTrackTablePlaceholder); diff --git a/src/library/previewbuttondelegate.cpp b/src/library/previewbuttondelegate.cpp index 4584dd3009..b244c68ac8 100644 --- a/src/library/previewbuttondelegate.cpp +++ b/src/library/previewbuttondelegate.cpp @@ -1,26 +1,46 @@ +#include "library/previewbuttondelegate.h" + #include <QPainter> #include <QPushButton> #include <QTableView> #include "control/controlproxy.h" -#include "library/previewbuttondelegate.h" #include "library/trackmodel.h" #include "mixer/playerinfo.h" #include "mixer/playermanager.h" #include "track/track.h" #include "widget/wlibrarytableview.h" -PreviewButtonDelegate::PreviewButtonDelegate(WLibraryTableView* parent, int column) - : TableItemDelegate(parent), - m_pTableView(parent), - m_isOneCellInEditMode(false), - m_colu |