@mtoc.app
3 followers 4 following 15 posts
Visually-rich local music library app for Linux by @3fz.org https://flathub.org/en/apps/org._3fz.mtoc
Posts Media Videos Starter Packs
mtoc.app
The result is subtle but creates good contrast at the edges of containers with a variety of contents: important for an interface that's entirely drawn on a "translucent" frosted glass effect. github.com/asa-degroff/...
mini player showing the effect
mtoc.app
but no part of the resulting image will actually be black. And since the blur is radial, there is also a subtle rounded effect at the corners, which closely emulates how light passing through a rectangular aperture looks in real life. A simpler linear gradient was tried, but didn't achieve this.
mtoc.app
Why create a composition layer 80px larger than the parent and then clip it to size? The blur effect works by averaging colors of neighboring pixels. With the black border being outside of the parent dimensions, black will be smoothly blended in,
mtoc.app
The effect: the composite layer has the blur applied (the blur radius is 64, the code may be a bit sloppy here from past experimentation). The opacity transition is set to 300ms inOutQuad for a smooth look. This effect is purely decorative, so the animation duration doesn't slow down the UX.
                ShaderEffectSource {
                    id: textureSource1
                    anchors.centerIn: parent
                    width: compositionLayer1.width
                    height: compositionLayer1.height
                    sourceItem: compositionLayer1
                    visible: false
                    live: true
                    hideSource: true
                }
                
                MultiEffect {
                    id: effect1
                    anchors.centerIn: parent
                    width: textureSource1.width
                    height: textureSource1.height
                    source: textureSource1
                    blurEnabled: true
                    blur: Math.min(1.0, root.blurRadius / 256.0)
                    blurMax: 64
                    visible: sourceImage1.status === Image.Ready || sourceImage1.status === Image.Loading
                    opacity: root.currentImageIndex === 0 ? root.backgroundOpacity : 0
                    autoPaddingEnabled: false
                    
                    Behavior on opacity {
                        NumberAnimation {
                            duration: 300
                            easing.type: Easing.InOutQuad
                        }
                    }
                }
            }
mtoc.app
The album art image: this is then placed on top of the black layer with 40px margins all around (centering it within the black rectangle). The size is capped at 512px (cropped to fit parent aspect ratio) for efficiency (smaller can make it look chunky, but anything larger will get blurred anyway).
                    Image {
                        id: sourceImage1
                        anchors.fill: parent
                        anchors.margins: 40
                        fillMode: Image.PreserveAspectCrop
                        cache: false  // Don't cache blurred backgrounds
                        asynchronous: true
                        source: root.image1Source
                        sourceSize.width: 512
                        sourceSize.height: 512
                        
                        onStatusChanged: {
                            if (status === Image.Error) {
                                console.warn("BlurredBackground: Failed to load image:", source);
                            }
                        }
                    }
                }
mtoc.app
Setup: source check, anchor to parent, clip: true. This sets the result to match the size of the parent container.
Composition layer with black padding: this is key to the subtle edge falloff. Another layer is created, 80px larger in both dimensions than the base layer, and filled with black.
    // Only create the image and blur effect if we have a valid source
    Loader {
        id: imageLoader
        anchors.fill: parent
        active: root.source != "" || root.image1Source != "" || root.image2Source != ""
        z: 1
        
        sourceComponent: Item {
            anchors.fill: parent
            clip: true  // Clip the overflowing content
            
            // Image layer 1
            Item {
                id: imageLayer1
                anchors.fill: parent
                
                // Composition layer with black padding
                Item {
                    id: compositionLayer1
                    anchors.centerIn: parent
                    width: parent.width + 80
                    height: parent.height + 80
                    visible: false
                    
                    Rectangle {
                        anchors.fill: parent
                        color: "black"
                    }
mtoc.app
First: why two layers? During animated opacity transitions, both images will be visible for the duration of the transition. This achieves the effect smoothly without transitioning to a solid color in between images. Loading them as two layers and changing the sources makes this easy.
    // Handle source changes and trigger crossfade
    onSourceChanged: {
        if (source != "") {
            // Update the non-visible layer with the new source
            if (currentImageIndex === 0) {
                // Layer 1 is visible, update layer 2
                // Clear the old source first to release memory
                if (image2Source != "") {
                    image2Source = ""
                }
                image2Source = source
            } else {
                // Layer 2 is visible, update layer 1
                // Clear the old source first to release memory
                if (image1Source != "") {
                    image1Source = ""
                }
                image1Source = source
            }
            // Toggle to the layer with the new image
            currentImageIndex = 1 - currentImageIndex
        } else {
            // Source is empty, clear both images to show black background
            image1Source = ""
            image2Source = ""
            currentImageIndex = 0
        }
    }
mtoc.app
Code vibe check: blurred background with edge brightness falloff. This effect is used wherever there's a blurred background derived from the album art: separate instances for the library pane and now playing pane/compact now playing bar, and in the mini player. 🧵
mtoc main window showing the blurred background effect
mtoc.app
mtoc 2.3.1 is releasing today: this patch fixes a bug where newly added lyrics would cause the lyrics display not to update properly when changing tracks, and fixes a bug where playing from the All Songs playlist after adding or removing tracks with the watcher enabled could cause a crash.
mtoc.app
Other new features toggleable in settings include:
- minimize to tray when closing the main window
- single-click to play tracks
mtoc.app
The new file watcher is implemented using the QFileSystemWatcher class to watch your chosen music directories for changes. Newly added (or removed) music will be automatically reflected in the library - no manual scanning or restarting required.
mtoc.app
External lyrics are automatically matched to audio files in the same directory. Exact base file name matches are paired, and fuzzy matching as a fallback finds the closest matching file name to pair lyrics with tracks. To populate your library with lyrics, check out LRCGET:
Install LRCGET on Linux | Flathub
Download synced LRC lyrics
flathub.org
mtoc.app
mtoc supports the standard lyrics tag for unsynced lyrics; embedded synced lyrics are supported using the SYLT standard for MP3 files.
External lyrics, synced and unsynced, are supported using the .lrc standard (.txt will also work). Shoutout to @s20n.dev for the lyrics implementation.
mtoc.app
Out today: mtoc 2.3. This update adds support for displaying lyrics, and a new file watcher enabling automatic library updates.
mtoc 2.3 promotional banner featuring a screenshot of the app showing the main window with library and lyrics displayed, "Get it on Flathub" badge, and the following text:

New in 2.3

Lyrics: embedded and external, synced lyrics with line highlighting and click-to-seek

File Watcher: fast, automatic library updates when adding and removing files from your music directory

New Settings Options: minimize to tray, single-click to play tracks
mtoc.app
Hello world! This is the official account for mtoc, a music player and library browsing app for Linux. Stay tuned for feature highlights, release notes, and development progress. mtoc aims to create a polished, visually-pleasing music experience with album art in the spotlight. Find it on Flathub.
screenshot of the mtoc main window, showing the library and now playing screens