Drumpad example (Qt Design Studio) - Final project¶
This example contains the final Qt Design Studio project of the Qt Design Studio integration tutorial. It contains all the necessary files to execute the project, including the Python code developed along the tutorial.
For more details, see the Qt Design Studio integration tutorial.
To download the initial project source code, visit Drumpad example (Qt Design Studio) - Initial project.
# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import sys
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
from autogen.settings import setup_qt_environment
from audio import * # noqa: F401,F403
def main():
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
setup_qt_environment(engine)
if not engine.rootObjects():
sys.exit(-1)
ex = app.exec()
del engine
return ex
if __name__ == "__main__":
sys.exit(main())
# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
# This file is automatically generated by Qt Design Studio.
import os
import sys
from pathlib import Path
from PySide6.QtQml import QQmlApplicationEngine
project_root = Path(__file__).parent.parent.parent
def setup_qt_environment(qml_engine: QQmlApplicationEngine):
"""
Load the QML application. Import the compiled resources when the application is deployed.
"""
qml_app_url = "DrumpadContent/App.qml"
if "__compiled__" in globals():
# Application has been deployed using pyside6-deploy
try:
import autogen.resources # noqa: F401
except ImportError:
resource_file = Path(__file__).parent / "resources.py"
print(
f"Error: No compiled resources found in {resource_file.absolute()}\n"
f"Please compile the resources using pyside6-rcc or pyside6-project build",
file=sys.stderr,
)
sys.exit(1)
qml_engine.addImportPath(":/")
qml_engine.load(f":/{qml_app_url}")
return
qml_engine.addImportPath(str(project_root.absolute()))
os.environ["QT_QUICK_CONTROLS_CONF"] = str(project_root / "qtquickcontrols2.conf")
qml_engine.load(str(project_root / qml_app_url))
# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from pathlib import Path
from PySide6.QtCore import QObject, Slot, QDirIterator
from PySide6.QtQml import QmlElement
from autogen.settings import project_root
QML_IMPORT_NAME = "Audio"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class AudioFilesModel(QObject):
@Slot(result=list)
def getModel(self):
if "__compiled__" in globals():
resource_prefix = ":/Sounds/"
iterator = QDirIterator(resource_prefix, QDirIterator.Subdirectories)
audio_files = []
while iterator.hasNext():
resource = iterator.next()
audio_files.append(resource.split(resource_prefix)[-1])
return audio_files
return list(p.name for p in Path(project_root / "Sounds").glob("*.wav"))
# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from PySide6.QtQml import QmlElement
from PySide6.QtCore import QObject, Slot, Property, Signal, QUrl
from PySide6.QtMultimedia import QSoundEffect
from autogen.settings import project_root
QML_IMPORT_NAME = "Audio"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class AudioEngine(QObject):
volumeChanged = Signal()
fileChanged = Signal()
isPlayingChanged = Signal()
decodingStatusChanged = Signal(QSoundEffect.Status, str)
def __init__(self, parent=None):
super().__init__(parent)
self._sound_effect = QSoundEffect()
self._sound_effect.playingChanged.connect(self.isPlayingChanged.emit) #
self._sound_effect.statusChanged.connect(self.reportStatus)
def reportStatus(self):
if self._sound_effect.status() == QSoundEffect.Status.Error:
self.decodingStatusChanged.emit(
QSoundEffect.Status.Error,
f"Error decoding file: {self._sound_effect.source().path()}",
)
else:
self.decodingStatusChanged.emit(self._sound_effect.status(), "")
@Slot(result=None)
def play(self):
self._sound_effect.play()
def volume(self):
return self._sound_effect.volume()
def setVolume(self, value):
self._sound_effect.setVolume(value)
self.volumeChanged.emit()
def file(self):
return self._sound_effect.source()
def setFile(self, value: QUrl):
if self._sound_effect.source() == value or value.isEmpty():
return
if "__compiled__" in globals():
self._sound_effect.setSource(f"qrc:/{value.toString()}")
else:
self._sound_effect.setSource(f"file:{project_root / value.toString()}")
self.fileChanged.emit()
def isPlaying(self):
return self._sound_effect.isPlaying()
volume = Property(float, volume, setVolume, notify=volumeChanged)
file = Property(QUrl, file, setFile, notify=fileChanged)
isPlaying = Property(bool, isPlaying, notify=isPlayingChanged)
# Copyright (C) 2025 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import struct
from PySide6.QtCore import Qt, Property, QUrl, Signal, QFile, QPointF
from PySide6.QtGui import QPen, QPainter
from PySide6.QtMultimedia import QAudioFormat, QAudioDecoder
from PySide6.QtQml import QmlElement
from PySide6.QtQuick import QQuickPaintedItem
QML_IMPORT_NAME = "Audio"
QML_IMPORT_MAJOR_VERSION = 1
@QmlElement
class WaveformItem(QQuickPaintedItem):
fileChanged = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._waveformData = []
self._background_color = Qt.black
audio_format = QAudioFormat()
audio_format.setChannelCount(1)
audio_format.setSampleRate(44100)
audio_format.setSampleFormat(QAudioFormat.Float)
self._file_url: QUrl | None = None
self._audio_file: QFile | None = None
self._decoder = QAudioDecoder()
self._decoder.setAudioFormat(audio_format)
self._decoder.bufferReady.connect(self.onBufferReady)
self._decoder.finished.connect(self.decoderFinished)
def file(self) -> QUrl | None:
return self._file_url
def setFile(self, value: QUrl):
if self._decoder.source() == value:
return
if self._audio_file and self._audio_file.isOpen():
self._audio_file.close()
self._waveformData = []
self._decoder.stop()
self._file_url = value
if "__compiled__" in globals():
path = self._file_url.toString().replace("qrc:/", ":/")
else:
path = self._file_url.path()
self._audio_file = QFile(path)
self._audio_file.open(QFile.ReadOnly)
self._decoder.setSourceDevice(self._audio_file)
self._decoder.start()
self.fileChanged.emit()
def paint(self, painter):
# Fill the bounding rectangle with the specified color
painter.fillRect(self.boundingRect(), self._background_color)
# If no waveform data is available, draw the text
if not self._waveformData:
painter.setPen(Qt.white)
painter.drawText(self.boundingRect(), Qt.AlignCenter, "Waveform not available")
return
painter.setRenderHint(QPainter.Antialiasing)
# Set the pen for drawing the waveform
pen = QPen(Qt.blue)
pen.setWidth(1)
painter.setPen(pen)
# Get container dimensions
rect = self.boundingRect()
data_size = len(self._waveformData)
# Calculate step size and center line
x_step = rect.width() / data_size
center_y = rect.height() / 2.0
# Draw the waveform as connected lines
for i in range(1, data_size):
x1 = (i - 1) * x_step
y1 = center_y - self._waveformData[i - 1] * center_y
x2 = i * x_step
y2 = center_y - self._waveformData[i] * center_y
painter.drawLine(QPointF(x1, y1), QPointF(x2, y2))
@staticmethod
def float_buffer_to_list(data):
# Calculate the number of 32-bit floats in the buffer
float_count = len(data) // 4 # Each float32 is 4 bytes
# Unpack the binary data into a list of floats
return list(struct.unpack(f"{float_count}f", data))
def onBufferReady(self):
buffer = self._decoder.read()
data = buffer.constData()
self._waveformData.extend(self.float_buffer_to_list(data))
self.update()
file: QUrl = Property(QUrl, file, setFile, notify=fileChanged)
def decoderFinished(self):
self._audio_file.close()
// prop: json-converted
// prop: auto-generated
import QmlProject
Project {
mainFile: "DrumpadContent/App.qml"
mainUiFile: "DrumpadContent/MainScreen.qml"
targetDirectory: "/opt/Drumpad"
enableCMakeGeneration: false
enablePythonGeneration: true
widgetApp: true
importPaths: [ "." ]
mockImports: [ "Mocks" ]
qdsVersion: "4.5"
quickVersion: "6.7"
qt6Project: true
qtForMCUs: false
multilanguageSupport: true
primaryLanguage: "en"
supportedLanguages: [ "en" ]
Environment {
QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
QT_AUTO_SCREEN_SCALE_FACTOR: "1"
QT_ENABLE_HIGHDPI_SCALING: "0"
QT_LOGGING_RULES: "qt.qml.connections=false"
QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
}
QmlFiles {
directory: "Drumpad"
}
QmlFiles {
directory: "DrumpadContent"
}
QmlFiles {
directory: "Generated"
}
Files {
directory: "Sounds"
filter: "*.mp3;*.wav"
}
QmlFiles {
directory: "Mocks/Audio"
}
Files {
files: [
"qtquickcontrols2.conf"
]
}
Files {
directory: "Drumpad"
filter: "qmldir"
}
Files {
directory: "DrumpadContent"
filter: "*.ttf;*.otf"
}
}
<RCC>
<qresource>
<file>Drumpad.qmlproject</file>
<file>Drumpad/AvailableSoundsComboBox.qml</file>
<file>Drumpad/CenteredFlow.qml</file>
<file>Drumpad/Constants.qml</file>
<file>Drumpad/PadButton.qml</file>
<file>Drumpad/qmldir</file>
<file>Drumpad/SoundEffectPlayer.qml</file>
<file>Drumpad/StyledSpinBox.qml</file>
<file>Drumpad/VolumeSlider.qml</file>
<file>DrumpadContent/App.qml</file>
<file>DrumpadContent/MainScreen.qml</file>
<file>DrumpadContent/qmldir</file>
<file>qtquickcontrols2.conf</file>
<file>Sounds/Bongo Loop 125bpm.wav</file>
<file>Sounds/Clap.wav</file>
<file>Sounds/Closed Hat.wav</file>
<file>Sounds/Kick Drum.wav</file>
<file>Sounds/Open Hat.wav</file>
<file>Sounds/Sine Bass Ebm.wav</file>
</qresource>
</RCC>
; This file can be edited to change the style of the application
; Read "Qt Quick Controls 2 Configuration File" for details:
; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html
[Controls]
Style=Basic
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import Audio
ComboBox {
id: root
property string currentFile: currentText ? `Sounds/${currentText}` : ""
required property int initialIndex
model: audioFilesModel.getModel()
background: Rectangle {
border.color: root.pressed ? Constants.primaryColor : Constants.secondaryColor
border.width: root.visualFocus ? 3 : 2
color: root.pressed ? Constants.secondaryColor : "black"
implicitHeight: 30
radius: 2
}
contentItem: Text {
color: "white"
elide: Text.ElideRight
leftPadding: 10
rightPadding: root.indicator.width + 10
text: root.displayText
verticalAlignment: Text.AlignVCenter
}
delegate: ItemDelegate {
id: delegate
required property int index
highlighted: root.highlightedIndex === index
background: Rectangle {
color: delegate.highlighted ? Constants.darkGray : "black"
implicitWidth: delegate.contentItem.implicitWidth
width: popup.width
}
contentItem: Text {
anchors.fill: parent
color: delegate.highlighted ? "#ff0000" : "white"
elide: Text.ElideRight
leftPadding: 10
text: root.model[delegate.index]
verticalAlignment: Text.AlignVCenter
}
}
indicator: Canvas {
id: canvas
contextType: "2d"
height: 8
width: 12
x: root.width - canvas.width - root.rightPadding
y: root.topPadding + (root.availableHeight - canvas.height) / 2
onPaint: {
let margin = 2;
context.reset();
context.lineWidth = 2;
context.strokeStyle = "white";
context.lineCap = "round";
context.beginPath();
context.moveTo(margin, margin);
context.lineTo(width / 2, height - margin);
context.lineTo(width - margin, margin);
context.stroke();
}
Connections {
function onPressedChanged() {
canvas.requestPaint();
}
target: root
}
}
popup: Popup {
id: popup
implicitHeight: contentItem.implicitHeight
implicitWidth: 200
padding: 2
y: root.height + 2
background: Rectangle {
border.color: Constants.primaryColor
border.width: 2
color: "black"
}
contentItem: ListView {
clip: true
currentIndex: root.highlightedIndex
implicitHeight: Math.min(contentHeight, 200)
model: popup.visible ? root.delegateModel : null
}
}
Component.onCompleted: {
currentIndex = root.initialIndex % model.length;
}
AudioFilesModel {
id: audioFilesModel
}
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
// A Flow layout that centers its children horizontally
// Note that the implementation adds unnecessary spacing in rows that are not full
Flow {
property int customMargin: (children.length && (children[0].width + spacing <= parentWidth))
? (parentWidth - rowWidth) / 2 + padding
: padding
property int parentWidth: parent.width - 2 * padding
property int rowCount: children.length ? parentWidth / (children[0].width + spacing) : 0
property int rowWidth: children.length
? rowCount * children[0].width + (rowCount - 1) * spacing + 2 * padding
: 0
anchors {
leftMargin: customMargin
rightMargin: customMargin
}
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
pragma Singleton
import QtQuick
QtObject {
readonly property string darkGray: "#333333"
readonly property string mediumGray: "#9B9B9B"
readonly property string primaryColor: "#FF0000"
readonly property string secondaryColor: "#8C0000"
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Shapes
Rectangle {
id: root
property bool isPlaying: false
property bool isError: false
property bool isLoading: false
property int cornerRadius: 10
signal pressed()
color: "transparent"
Shape {
anchors.fill: parent
ShapePath {
strokeColor: "black"
strokeWidth: 2
fillGradient: RadialGradient {
centerRadius: root.height
centerX: root.width / 2
centerY: root.height / 2
focalX: centerX
focalY: centerY
GradientStop {
position: 0
color: {
if (isError)
return "black";
if (isLoading)
return "yellow";
if (isPlaying)
return Qt.darker(Constants.primaryColor, 1.25);
return Qt.darker(Constants.secondaryColor, 1.25);
}
}
GradientStop {
position: 0.5
color: {
if (isError)
return Constants.darkGray;
if (isLoading)
return "orange";
if (isPlaying)
return Constants.primaryColor;
return Constants.secondaryColor;
}
}
}
// Rounded shape path
PathMove {
x: root.cornerRadius
y: 0
}
PathQuad {
controlX: 0
controlY: 0
x: 0
y: root.cornerRadius
}
PathLine {
x: 0
y: root.height - root.cornerRadius
}
PathQuad {
controlX: 0
controlY: root.height
x: root.cornerRadius
y: root.height
}
PathLine {
x: root.width - root.cornerRadius
y: root.height
}
PathQuad {
controlX: root.width
controlY: root.height
x: root.width
y: root.height - root.cornerRadius
}
PathLine {
x: root.width
y: root.cornerRadius
}
PathQuad {
controlX: root.width
controlY: 0
x: root.width - root.cornerRadius
y: 0
}
PathLine {
x: root.cornerRadius
y: 0
}
}
}
MouseArea {
anchors.fill: parent
onClicked: root.pressed()
}
}
module Drumpad
AvailableSoundsComboBox 1.0 AvailableSoundsComboBox.qml
SoundEffectPlayer 1.0 SoundEffectPlayer.qml
CenteredFlow 1.0 CenteredFlow.qml
VolumeSlider 1.0 VolumeSlider.qml
StyledSpinBox 1.0 StyledSpinBox.qml
PadButton 1.0 PadButton.qml
singleton Constants 1.0 Constants.qml
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Layouts
import QtQuick.Dialogs
import QtMultimedia
import Drumpad
import Audio
Rectangle {
id: root
property string decodingError: ""
required property int index
property int status: SoundEffect.Null
property bool isLoading: status == SoundEffect.Loading
property bool isError: status == SoundEffect.Error || status == SoundEffect.Null
property bool isReady: status == SoundEffect.Ready
function play() {
if (root.status == SoundEffect.Ready) {
audioEngine.play();
}
}
color: Constants.darkGray
implicitHeight: layout.implicitHeight + 2 * layout.anchors.margins
implicitWidth: layout.implicitWidth + 2 * layout.anchors.margins
radius: 10
onDecodingErrorChanged: {
if (status == SoundEffect.Error && root.decodingError) {
errorMessageDialog.text = root.decodingError;
errorMessageDialog.open();
}
}
AudioEngine {
id: audioEngine
file: availableSoundsComboBox.currentFile
volume: volumeSlider.value
onDecodingStatusChanged: (status, error) => {
root.status = status;
if (status == SoundEffect.Error && error) {
root.decodingError = error;
} else {
root.decodingError = "";
}
}
}
MessageDialog {
id: errorMessageDialog
buttons: MessageDialog.Ok
title: "Error decoding file"
}
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: 10
spacing: 10
RowLayout {
spacing: 10
Text {
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
color: "white"
text: `Player ${root.index + 1}`
}
AvailableSoundsComboBox {
id: availableSoundsComboBox
Layout.alignment: Qt.AlignCenter
initialIndex: root.index
}
}
WaveformItem {
id: waveformItem
file: audioEngine.file
height: 100
width: 300
}
Row {
Layout.alignment: Qt.AlignCenter
spacing: 10
PadButton {
id: padRectangle
height: 100
width: 100
isPlaying: audioEngine.isPlaying
isError: root.isError
isLoading: root.isLoading
onPressed: root.play()
}
VolumeSlider {
id: volumeSlider
height: padRectangle.height
value: 0.75
width: 16
}
}
}
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Controls
SpinBox {
id: root
property int innerPadding: 10
height: contentItem.implicitHeight + innerPadding
width: contentItem.width + up.indicator.implicitWidth + down.indicator.implicitWidth
background: Rectangle {
border.color: Constants.secondaryColor
}
contentItem: Text {
color: "black"
height: parent.height
horizontalAlignment: Text.AlignHCenter
text: root.textFromValue(root.value, root.locale)
verticalAlignment: Text.AlignVCenter
width: implicitWidth + innerPadding * 2
}
down.indicator: Rectangle {
border.color: Constants.secondaryColor
color: root.down.pressed ? Constants.mediumGray : enabled ? Constants.darkGray : "black"
height: parent.height
implicitWidth: downText.implicitWidth + innerPadding * 2
x: root.mirrored ? parent.width - width : 0
Text {
id: downText
anchors.fill: parent
color: "white"
font.pixelSize: Math.round(root.font.pixelSize * 1.5)
fontSizeMode: Text.Fit
horizontalAlignment: Text.AlignHCenter
text: "-"
verticalAlignment: Text.AlignVCenter
}
}
up.indicator: Rectangle {
border.color: Constants.secondaryColor
color: root.up.pressed ? Constants.mediumGray : enabled ? Constants.darkGray : "black"
height: parent.height
implicitWidth: upText.implicitWidth + innerPadding * 2
x: root.mirrored ? 0 : parent.width - width
Text {
id: upText
anchors.centerIn: parent
anchors.fill: parent
color: "white"
font.pixelSize: Math.round(root.font.pixelSize * 1.5)
fontSizeMode: Text.Fit
horizontalAlignment: Text.AlignHCenter
text: "+"
verticalAlignment: Text.AlignVCenter
}
}
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Controls
Slider {
id: root
orientation: Qt.Vertical
padding: 0
background: Rectangle {
color: Constants.mediumGray
implicitHeight: root.height
implicitWidth: root.width
radius: width / 2
Rectangle {
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
color: Qt.lighter(Constants.primaryColor, 1 - (root.visualPosition * 0.3))
height: (1 - root.visualPosition) * parent.height + (root.visualPosition * handle.height)
radius: parent.width / 2
width: parent.width
}
}
handle: Rectangle {
border.color: "#b0b0b0"
border.width: 1
color: root.pressed ? "#e0e0e0" : "#ffffff"
height: root.width
radius: width / 2
width: root.width
x: root.availableWidth / 2 - height / 2
y: root.visualPosition * (root.availableHeight - height)
}
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15
import QtQuick.Window 2.15
import Drumpad 1.0
Window {
id: root
height: 800
title: "Drumpad"
visible: true
width: 1200
MainScreen {
id: mainScreen
anchors.fill: parent
}
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Drumpad
import Audio
Rectangle {
id: root
property QtObject soundEffectPlayer: Qt.createComponent("../Drumpad/SoundEffectPlayer.qml",
Component.PreferSynchronous)
color: "black"
focus: true
Component.onCompleted: {
// Initialize the default sound effect players
for (var i = 0; i < audioPlayersSpinBox.value; i++) {
root.soundEffectPlayer.createObject(soundEffectPlayersFlow, {
index: i
});
}
}
Keys.onPressed: event => {
if (event.key < Qt.Key_1 || event.key > Qt.Key_9) {
// Ignore key out of scope
return;
}
let digit = event.key - Qt.Key_1;
if (digit < soundEffectPlayersFlow.children.length) {
soundEffectPlayersFlow.children[digit].play();
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
Row {
id: audioPlayersCountRow
Layout.alignment: Qt.AlignHCenter
spacing: 5
Text {
anchors.verticalCenter: parent.verticalCenter
color: "white"
text: "Audio players:"
}
StyledSpinBox {
id: audioPlayersSpinBox
value: 5
onValueModified: {
let soundPlayersCount = soundEffectPlayersFlow.children.length;
if (audioPlayersSpinBox.value < soundPlayersCount) {
// Remove extra sound effect players
soundEffectPlayersFlow.children.length = audioPlayersSpinBox.value;
return;
}
if (audioPlayersSpinBox.value < soundPlayersCount) {
return;
}
// Create more sound effect players
for (var i = soundPlayersCount; i < audioPlayersSpinBox.value; i++) {
root.soundEffectPlayer.createObject(soundEffectPlayersFlow, {
index: i
});
}
}
}
}
ScrollView {
Layout.fillHeight: true
Layout.fillWidth: true
contentWidth: width
background: Rectangle {
color: "#232323"
}
CenteredFlow {
id: soundEffectPlayersFlow
anchors.fill: parent
padding: 10
spacing: 10
}
}
}
}
module DrumpadContent
App 1.0 App.qml
MainScreen 1.0 MainScreen.qml
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtMultimedia
Item {
id: root
property double volume
property url file
MediaPlayer {
id: player
source: file
audioOutput: AudioOutput {}
}
onVolumeChanged : {
console.log("Mock: VolumeChanaged ", volume )
}
function play() {
console.log("Mock: play()")
player.play()
}
}
module Audio
AudioEngine 1.0 AudioEngine.qml
WaveformItem 1.0 WaveformItem.qml
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick.Controls
Rectangle {
id: root
width: 1920
height: 1080
color: "blue"
property url file
}
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
Item {
getFiles: function() {
console.log("AudioFilesModel mock: getFiles()")
}
}
module Components
AudioFilesModel 1.0 AudioFilesModel.qml