Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,79 @@ jobs:
name: ${{ matrix.artifacts_name }}
path: ${{ matrix.artifacts_path }}

build-flatpak:
name: "Flatpak"
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.10
options: --privileged
volumes:
- /usr:/host/usr
- /opt:/host/opt
strategy:
matrix:
variant:
- arch: x86_64
runner: ubuntu-24.04
- arch: aarch64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.variant.runner }}
steps:
- name: "Recover host disk space"
run: |
rm -rf /host/opt/hostedtoolcache/CodeQL
rm -rf /host/opt/hostedtoolcache/go
rm -rf /host/usr/local/lib/android
rm -rf /host/usr/local/.ghcup
rm -rf /host/usr/local/share/powershell
rm -rf /host/usr/share/swift
rm -rf /host/usr/share/dotnet

- name: "Check out repository"
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: "Store Git version"
run: |
git config --global --add safe.directory "${GITHUB_WORKSPACE}"
GIT_DESC=$(git describe --always --first-parent --dirty=-modified)
if [ -z "$GIT_DESC" ]; then
GIT_DESC="unknown"
fi
echo "GIT_DESC=$GIT_DESC" >> $GITHUB_ENV

- name: "Build Flatpak"
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
manifest-path: packaging/flatpak/org.mixxx.Mixxx.yaml
arch: ${{ matrix.variant.arch }}
build-bundle: false
upload-artifact: false

- name: "Create Flatpak bundle"
run: |
flatpak build-bundle repo \
--arch=${{ matrix.variant.arch }} \
Mixxx-${GIT_DESC}-${{ matrix.variant.arch }}.flatpak org.mixxx.Mixxx

- name: "Create Debug extension"
run: |
flatpak build-bundle repo \
--arch=${{ matrix.variant.arch }} \
--runtime Mixxx-${GIT_DESC}-${{ matrix.variant.arch }}.Debug.flatpak org.mixxx.Mixxx.Debug

- name: "Upload Flatpak bundle"
uses: actions/upload-artifact@v6
with:
name: Flatpak ${{ matrix.variant.arch }}
path: Mixxx-${{ env.GIT_DESC }}-${{ matrix.variant.arch }}.flatpak

- name: "Upload Debug extension"
uses: actions/upload-artifact@v6
with:
name: Flatpak Debug Extension ${{ matrix.variant.arch }}
path: Mixxx-${{ env.GIT_DESC }}-${{ matrix.variant.arch }}.Debug.flatpak

update_manifest:
name: "Update manifest file on download server"
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion lib/reverb/Reverb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ void MixxxPlateX2::processBuffer(const sample_t* in, sample_t* out, const uint f
double damp = exp(-M_PI * (.0005+.9995*dampingParam));
tank.damping[0].set(damp);
tank.damping[1].set(damp);
RampingValue<sample_t> send(pow(currentSend, 1.53), previousSend, frames);
RampingValue<sample_t> send(pow(previousSend, 1.53), pow(currentSend, 1.53), frames);

// the modulated lattices interpolate, which needs truncated float
DSP::FPTruncateMode _truncate;
Expand Down
8 changes: 4 additions & 4 deletions src/effects/backends/builtin/echoeffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ void EchoEffect::processChannel(
int read_position = pGroupState->write_position;
decrementRing(&read_position, delay_samples, pGroupState->delay_buf.size());

RampingValue<CSAMPLE_GAIN> send(send_current,
pGroupState->prev_send,
RampingValue<CSAMPLE_GAIN> send(pGroupState->prev_send,
send_current,
engineParameters.framesPerBuffer());
// Feedback the delay buffer and then add the new input.

RampingValue<CSAMPLE_GAIN> feedback(feedback_current,
pGroupState->prev_feedback,
RampingValue<CSAMPLE_GAIN> feedback(pGroupState->prev_feedback,
feedback_current,
engineParameters.framesPerBuffer());

int rampIndex = 0;
Expand Down
53 changes: 48 additions & 5 deletions src/library/dao/playlistdao.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
#include "util/math.h"

PlaylistDAO::PlaylistDAO()
: m_pAutoDJProcessor(nullptr) {
: m_currentHistoryPlaylist(kInvalidPlaylistId),
m_pAutoDJProcessor(nullptr) {
}

void PlaylistDAO::initialize(const QSqlDatabase& database) {
Expand Down Expand Up @@ -330,19 +331,35 @@ bool PlaylistDAO::deleteUnlockedPlaylists(QStringList&& idStringList) {
}

bool PlaylistDAO::deleteAllUnlockedPlaylistsWithFewerTracks(
PlaylistDAO::HiddenType type, int minNumberOfTracks) {
PlaylistDAO::HiddenType type,
int minNumberOfTracks,
bool skipCurrHistory) {
// Note: this slot is also called after purging tracks in order to delete
// now empty history playlists.
// Though, if the current History is now also empty, we must not delete that!
// Else the following session log is lost -- or rather not recorded in the
// first place since the id passed to appendTrackToPlaylist() does not exist
// anymore.
// skipCurrHistory prevents that.
VERIFY_OR_DEBUG_ASSERT(minNumberOfTracks > 0) {
return false; // nothing to do, probably unintended invocation
}

QSqlQuery query(m_database);
query.prepare(QStringLiteral(
QString queryString = QStringLiteral(
"SELECT id FROM Playlists "
"WHERE (SELECT count(playlist_id) FROM PlaylistTracks WHERE "
"Playlists.ID = PlaylistTracks.playlist_id) < :length AND "
"Playlists.hidden = :hidden AND Playlists.locked = 0"));
"Playlists.hidden = :hidden AND Playlists.locked = 0");
if (skipCurrHistory) {
queryString.append(QStringLiteral(" AND Playlists.ID != :currHistoryId"));
}
query.prepare(queryString);
query.bindValue(":hidden", static_cast<int>(type));
query.bindValue(":length", minNumberOfTracks);
if (skipCurrHistory) {
query.bindValue(":currHistoryId", m_currentHistoryPlaylist);
}
if (!query.exec()) {
LOG_FAILED_QUERY(query);
return false;
Expand All @@ -352,6 +369,11 @@ bool PlaylistDAO::deleteAllUnlockedPlaylistsWithFewerTracks(
while (query.next()) {
idStringList.append(query.value(0).toString());
}

if (idStringList.isEmpty()) {
return false;
}

qInfo() << "Prepared deletion of" << idStringList.size() << "playlists of type" << type
<< "that contain fewer than" << minNumberOfTracks << "tracks";

Expand Down Expand Up @@ -481,9 +503,29 @@ bool PlaylistDAO::removeTracksFromPlaylist(int playlistId, int startIndex) {
return true;
}

bool PlaylistDAO::playlistExists(const int playlistId) const {
ScopedTransaction transaction(m_database);
QSqlQuery query(m_database);
query.prepare(QStringLiteral("SELECT id FROM Playlists WHERE id = :id"));
query.bindValue(":id", playlistId);

if (!query.exec()) {
LOG_FAILED_QUERY(query);
return false;
}

if (query.next()) {
// id is guaranteed to be unique, so we can return here
return true;
}
// not found
return false;
}

bool PlaylistDAO::appendTracksToPlaylist(const QList<TrackId>& trackIds, const int playlistId) {
// qDebug() << "PlaylistDAO::appendTracksToPlaylist"
// << QThread::currentThread() << m_database.connectionName();
DEBUG_ASSERT(playlistExists(playlistId));

// Start the transaction
ScopedTransaction transaction(m_database);
Expand Down Expand Up @@ -1094,7 +1136,8 @@ void PlaylistDAO::removeTracksFromPlaylists(const QList<TrackId>& trackIds, bool
transaction.commit();

// We may now have empty history playlists. Remove them.
deleteAllUnlockedPlaylistsWithFewerTracks(PlaylistDAO::PLHT_SET_LOG, 1);
// Note: does not delete current History playlist.
deleteAllUnlockedPlaylistsWithFewerTracks(PlaylistDAO::PLHT_SET_LOG, 1, true);

// update the sidebar
emit playlistContentChanged(playlistIds);
Expand Down
10 changes: 9 additions & 1 deletion src/library/dao/playlistdao.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class PlaylistDAO : public QObject, public virtual DAO {
/// Needs to be called inside a transaction.
/// @return true on success, false on error
bool deleteAllUnlockedPlaylistsWithFewerTracks(const PlaylistDAO::HiddenType type,
int minNumberOfTracks);
int minNumberOfTracks,
bool skipCurrHistory = false);
// Rename a playlist
void renamePlaylist(const int playlistId, const QString& newName);
// Lock or unlock a playlist
Expand All @@ -57,6 +58,8 @@ class PlaylistDAO : public QObject, public virtual DAO {
int setPlaylistsLocked(const QSet<int>& playlistIds, const bool lock);
// Find out the state of a playlist lock
bool isPlaylistLocked(const int playlistId) const;
// Check if a playlist exists
bool playlistExists(const int playlistId) const;
// Append a list of tracks to a playlist
bool appendTracksToPlaylist(const QList<TrackId>& trackIds, const int playlistId);
// Append a track to a playlist
Expand Down Expand Up @@ -120,6 +123,10 @@ class PlaylistDAO : public QObject, public virtual DAO {

void getPlaylistsTrackIsIn(TrackId trackId, QSet<int>* playlistSet) const;

void setCurrentHistoryPlaylistId(int id) {
m_currentHistoryPlaylist = id;
}

void setAutoDJProcessor(AutoDJProcessor* pAutoDJProcessor);

signals:
Expand Down Expand Up @@ -151,6 +158,7 @@ class PlaylistDAO : public QObject, public virtual DAO {
void populatePlaylistMembershipCache();

QMultiHash<TrackId, int> m_playlistsTrackIsIn;
int m_currentHistoryPlaylist;
AutoDJProcessor* m_pAutoDJProcessor;
DISALLOW_COPY_AND_ASSIGN(PlaylistDAO);
};
2 changes: 2 additions & 0 deletions src/library/trackset/setlogfeature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ void SetlogFeature::slotGetNewPlaylist() {
<< set_log_name;
} else {
m_recentTracks.clear();
m_playlistDao.setCurrentHistoryPlaylistId(m_currentPlaylistId);
}

// reload child model again because the 'added' signal fired by PlaylistDAO
Expand Down Expand Up @@ -447,6 +448,7 @@ void SetlogFeature::slotJoinWithPrevious() {

// Change current setlog
m_currentPlaylistId = previousPlaylistId;
m_playlistDao.setCurrentHistoryPlaylistId(m_currentPlaylistId);
}
qDebug() << "slotJoinWithPrevious() current:"
<< clickedPlaylistId
Expand Down
40 changes: 35 additions & 5 deletions src/widget/wlibrarytableview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,45 @@ bool WLibraryTableView::restoreTrackModelState(
verticalScrollBar()->setValue(state->verticalScrollPosition);
horizontalScrollBar()->setValue(state->horizontalScrollPosition);

auto* pSelection = selectionModel();
pSelection->clearSelection();
// Build a selection range rather than selecting each track individually,
// which can lag the GUI by spamming selectionChanged() handlers.
QItemSelectionModel* pSelectionModel = selectionModel();
pSelectionModel->clearSelection();
QItemSelection newSelection;
QModelIndexList selectedRows = state->selectedRows;
QModelIndex topLeft;
QModelIndex bottomRight;
if (!selectedRows.isEmpty()) {
for (auto index : std::as_const(selectedRows)) {
pSelection->select(index,
QItemSelectionModel::Select | QItemSelectionModel::Rows);
// In saveTrackModelState() we fill state->selectedRows with the sorted
// rows, hence no need to sort here.
for (const QModelIndex& index : std::as_const(selectedRows)) {
if (!topLeft.isValid()) {
// start new range. only done once for first row
topLeft = index;
bottomRight = index;
continue;
}

if (index.row() == bottomRight.row() + 1) {
// continuous range
bottomRight = index;
continue;
} else {
// prev index was end of range, add current range to selection
// and start a new one
newSelection.select(topLeft, bottomRight);
topLeft = index;
bottomRight = index;
}
}

// If we reached end, submit the last selection
if (bottomRight == selectedRows.last()) {
newSelection.select(topLeft, bottomRight);
}
}
pSelectionModel->select(newSelection,
QItemSelectionModel::Select | QItemSelectionModel::Rows);

QModelIndex currIndex = state->currentIndex;
restoreCurrentIndex(currIndex);
Expand Down
Loading