diff --git a/.github/actions/initialize-build-environment/action.yml b/.github/actions/initialize-build-environment/action.yml
index 18aed6d3..12e10df1 100644
--- a/.github/actions/initialize-build-environment/action.yml
+++ b/.github/actions/initialize-build-environment/action.yml
@@ -39,7 +39,7 @@ runs:
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew update
- brew install ninja
+ brew install ninja ccache imagemagick create-dmg
- name: Install Qt
uses: jurplel/install-qt-action@v4
diff --git a/.github/actions/initialize-vcpkg/action.yml b/.github/actions/initialize-vcpkg/action.yml
index e19dd5ab..1d083ef5 100644
--- a/.github/actions/initialize-vcpkg/action.yml
+++ b/.github/actions/initialize-vcpkg/action.yml
@@ -31,7 +31,7 @@ runs:
QT_DIR: ${{ env.Qt_ROOT_DIR }}/lib/cmake/Qt6
Qt6_DIR: ${{ env.Qt_ROOT_DIR }}/lib/cmake/Qt6
VCPKG_CMAKE_RELEASE_BUILD_TYPE: "RelWithDebInfo"
- VCPKG_KEEP_ENV_VARS: "QT_DIR;Qt6_DIR;VCPKG_CMAKE_RELEASE_BUILD_TYPE;VCPKG_BUILD_TYPE"
+ VCPKG_KEEP_ENV_VARS: "QT_DIR;Qt6_DIR;VCPKG_CMAKE_RELEASE_BUILD_TYPE;VCPKG_BUILD_TYPE;MACOSX_DEPLOYMENT_TARGET"
shell: pwsh
run: |
if (!(Test-Path $env:VCPKG_DEFAULT_BINARY_CACHE)) {
diff --git a/.github/instructions/viewmodel-binding.instructions.md b/.github/instructions/viewmodel-binding.instructions.md
new file mode 100644
index 00000000..50eddd12
--- /dev/null
+++ b/.github/instructions/viewmodel-binding.instructions.md
@@ -0,0 +1,103 @@
+# View-Model ↔ Document Binding Prompt
+
+Use this prompt to guide new view-model bindings for future document elements. Keep property specifics out; focus on state design, controller-driven transitions, transactions, and synchronization patterns. Derive patterns from existing implementations (e.g., `TrackViewModelContextData`, `LabelViewModelContextData`, `TempoViewModelContextData`).
+
+## Core Goals
+- Mirror document collections to view-model collections with clear ownership and mapping tables in both directions.
+- Drive UI interactions through controllers; never mutate document state directly from QML.
+- Guard against infinite loops by conditioning view→doc updates on active states.
+- Wrap mutating operations in transactions with start/commit/abort semantics tied to state entry/exit.
+
+- Instrument every state with entry/exit logging (use `qCInfo` with a per-context logging category) to trace flows during debugging, even for states without handlers.
+
+## State Machine Design
+- Build a `QStateMachine` with explicit states for idle, rubber-band selection, move/drag, edit/adjust flows, and per-property operations as needed.
+- Keep transitions driven by signals emitted from interaction controllers and internal guards (e.g., started/not-started, commit/abort, finish).
+- Example (move flow, list rotation):
+ - `idle` → `movePending` on `moveTransactionWillStart` (from controller).
+ - `movePending` → `moveProcessing` on `moveTransactionStarted`; → `idle` on `moveTransactionNotStarted`.
+ - `moveProcessing` → `moveCommitting` on `moveTransactionWillCommit`; → `moveAborting` on `moveTransactionWillAbort`.
+ - `moveCommitting`/`moveAborting` → `idle` (reset guards).
+- Example (edit flow, text-like):
+ - `idle` → `namePending` on `nameTransactionWillStart`.
+ - `namePending` → `nameProgressing` on `nameTransactionStarted`; → `idle` if not started.
+ - `nameProgressing` → `nameCommitting` on commit; → `nameAborting` on abort.
+ - `nameCommitting`/`nameAborting` → `idle`.
+- Rubber-band selection: `idle` → `rubberBandDragging` on start, back to `idle` on finish.
+
+## Controller-Driven Transitions
+- Wire controller signals to emit local signals that the state machine consumes (two patterns):
+ 1) **Started/Committed/Aborted**: drag/move and text edits use started/commit/abort triplets.
+ 2) **Started/Finished**: toggle/slider/height edits use started/finished pairs.
+- Set the current target item/index when the controller signals a start; clear it on commit/finish/abort handlers.
+- For rotations or list moves: only propagate view→doc when in the move-processing state; otherwise apply doc→view rotations.
+
+## Transactions
+- Begin a transaction when entering the corresponding "pending" state. Abort immediately if the controller could not start.
+- On commit states: if the new value differs, write to the document and `commitTransaction` with a descriptive label; otherwise `abortTransaction`.
+- On abort states: always `abortTransaction` and reset local guards (`target`, flags like `moveChanged`).
+- Track whether any change occurred during move/drag (`moveChanged`) to avoid committing no-op transactions.
+
+## Synchronization Patterns
+- Maintain bidirectional maps: `doc -> view` and `view -> doc`. Insert/remove bindings on collection signals (`itemInserted`/`itemRemoved`), not "aboutTo" when you need the item fully constructed.
+- When binding a new item:
+ - Create the view-model item, insert into both maps and the view-model collection at the correct index.
+ - Connect doc→view signals to update view items, guarded by equality checks.
+ - Connect view→doc signals but gate them with state checks (only honor during the relevant progressing/doing states; otherwise revert the view to the doc value).
+ - Initialize view properties from the doc model after wiring connections.
+- Selection sync: listen to document selection model `itemSelected` and mark the view item selected; initialize selection for pre-selected items after binding.
+- Rotation sync: doc→view rotations apply when *not* moving; view→doc rotations apply only while the move state is active, and should mark a change flag.
+
+## Example Snippets
+- **Doc→View guarded update** (avoid loops):
+ ```cpp
+ connect(control, &ControlType::propertyChanged, viewItem, [=](auto value) {
+ if (viewItem->property() == value) return;
+ viewItem->setProperty(value);
+ });
+ ```
+- **View→Doc gated by state**:
+ ```cpp
+ connect(viewItem, &ViewType::propertyChanged, docItem, [=] {
+ if (!stateMachine->configuration().contains(propertyProgressingState)) {
+ viewItem->setProperty(docItem->property());
+ return;
+ }
+ // defer actual write to commit handler
+ });
+ ```
+- **Transaction commit handler**:
+ ```cpp
+ void ContextData::onNameCommittingStateEntered() {
+ if (!target || nameTxId == Invalid) { target = {}; return; }
+ auto viewItem = viewMap.value(target);
+ if (viewItem->name() == target->name()) {
+ tx->abortTransaction(nameTxId);
+ } else {
+ target->setName(viewItem->name());
+ tx->commitTransaction(nameTxId, tr("Renaming item"));
+ }
+ nameTxId = {}; target = {};
+ }
+ ```
+- **Rotate handling**:
+ ```cpp
+ connect(docList, &List::rotated, this, [=](int l, int m, int r) {
+ if (stateMachine->configuration().contains(moveProcessingState)) return;
+ viewList->rotate(l, m, r);
+ });
+ connect(viewList, &ViewList::rotated, this, [=](int l, int m, int r) {
+ if (!stateMachine->configuration().contains(moveProcessingState)) return;
+ moveChanged = true;
+ docList->rotate(l, m, r);
+ });
+ ```
+
+## Implementation Checklist
+- Define states and transitions before binding to controllers; start the state machine immediately.
+- Create controllers via context helper methods; hook all relevant signals to emit local transition signals and set the current target.
+- Bind document collections first, then replay existing selection to the view.
+- For each commit/finish handler: compare values, write document, commit transaction; otherwise abort. Always reset `target` and flags.
+- Keep all strings ASCII; add concise comments only where non-obvious.
+
+Use this prompt verbatim when extending bindings to new document elements to maintain consistent interaction, transaction, and synchronization behavior across the codebase.
diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml
index 03dca6ce..7dd6dc8c 100644
--- a/.github/workflows/dev-build.yml
+++ b/.github/workflows/dev-build.yml
@@ -16,6 +16,7 @@ on:
- 'LICENSE'
- 'crowdin.yml'
- '.github/**'
+ - '**/translations/*.ts'
workflow_dispatch:
inputs:
identifier:
@@ -40,16 +41,16 @@ jobs:
os:
- windows-2025
# - ubuntu-24.04
- # - macos-15
-
+ - macos-15
env:
- QT_VERSION: 6.9.2
+ QT_VERSION: 6.10.1
VCPKG_REF: 74e6536215718009aae747d86d84b78376bf9e09
INNOSETUP_REF: is-6_5_4
VERSION_IDENTIFIER: ${{ github.sha }}${{ github.event.inputs.identifier && '.' || '' }}${{ github.event.inputs.identifier }}
BUILD_DIR: ${{ github.workspace }}/build/build
INSTALL_DIR: ${{ github.workspace }}/build/install
CCACHE_DIR: ${{ github.workspace }}/build/ccache
+ MACOSX_DEPLOYMENT_TARGET: 13.0
runs-on: ${{ matrix.os }}
@@ -87,7 +88,10 @@ jobs:
-InstallDir $env:INSTALL_DIR `
-VersionIdentifier $env:VERSION_IDENTIFIER `
${{ github.event.inputs.use_ccache == 'true' && '-CCache' || '' }}
- Write-Output ARTIFACT_NAME=$($output.ApplicationName)_$($output.Semver -replace '[\.\-\+]', '_') >> $env:GITHUB_ENV
+ Write-Output ARTIFACT_NAME=$($output.ApplicationName)_$($output.Semver -replace '[\.\-\+]', '_')_${{ runner.os }}_${{ runner.arch }} >> $env:GITHUB_ENV
+ Write-Output APPLICATION_SEMVER=$($output.Semver) >> $env:GITHUB_ENV
+ Write-Output APPLICATION_DISPLAY_NAME=$($output.ApplicationDisplayName) >> $env:GITHUB_ENV
+ Write-Output APPLICATION_NAME=$($output.ApplicationName) >> $env:GITHUB_ENV
Write-Output INSTALLER_FILE_BASE=$($output.InstallerFileBase) >> $env:GITHUB_ENV
- name: Save CCache cache
@@ -102,11 +106,22 @@ jobs:
$output = & ./scripts/ci/Collect-Symbol-Files.ps1 -VcpkgRootDir $env:VCPKG_ROOT_DIR -InstallDir $env:INSTALL_DIR
Write-Output SYMBOL_FILES_PATH=$($output.Path) >> $env:GITHUB_ENV
- - name: Pack
+ - name: Create InnoSetup installer (Windows)
+ if: ${{ runner.os == 'Windows' }}
run: |
$output = & ./scripts/ci/Pack.ps1 -BuildDir $env:BUILD_DIR -InstallerFileBase $env:INSTALLER_FILE_BASE -InnoSetupCommit $env:INNOSETUP_REF
Write-Output PACKAGE_PATH=$($output.Path) >> $env:GITHUB_ENV
+ - name: Create DMG installer (macOS)
+ if: ${{ runner.os == 'macOS' }}
+ run: |
+ $output = & ./scripts/ci/Create-DMG.ps1 `
+ -AppPath $(Join-Path $env:INSTALL_DIR $env:APPLICATION_NAME'.app') `
+ -Semver $env:APPLICATION_SEMVER `
+ -ApplicationDisplayName $env:APPLICATION_DISPLAY_NAME `
+ -InstallerFileBase $env:INSTALLER_FILE_BASE
+ Write-Output PACKAGE_PATH=$($output) >> $env:GITHUB_ENV
+
- name: Upload symbol files
uses: actions/upload-artifact@v4
with:
diff --git a/README.md b/README.md
index c7ad8a86..c0b2a3de 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,55 @@
-# DiffScope Project
\ No newline at end of file
+# DiffScope
+
+A free, professional singing-voice-synthesis editor powered by [DiffSinger](https://github.com/openvpi/DiffSinger)
+
+> [!NOTE]
+> This project is currently under development. Anything related to the project is subject to change.
+
+## Looking for Contributors
+
+This project is currently under active development, and we are looking for contributors to help develop it.
+
+Preferred Skills:
+- C++ (front-end core logic)
+- Qt QML (front-end GUI)
+- Golang (backend)
+
+Additionally, familiarity with singing voice synthesis (SVS), digital audio processing, or related fields is highly appreciated.
+
+If you are interested in contributing or collaborating, please feel free to reach out via Issues.
+
+## Progress
+
+- [x] Application GUI shell
+- [x] Arrangement and piano roll editors
+- [x] Basic audio processing functionalities
+- [ ] Phoneme and parameter editors
+- [ ] Audio playback
+- [ ] Integration of synthesis engine
+
+## Build
+
+1. Install essential tools for C/C++ development and Qt.
+2. Clone this repository recursively.
+
+ ```bash
+ git clone --recursive https://github.com/diffscope/diffscope-project.git
+ ```
+
+3. Install dependencies via Vcpkg.
+
+ ```bash
+ vcpkg install --x-manifest-root=/path/to/diffscope-project/scripts/vcpkg-manifest --x-install-root=/path/to/vcpkg/installed
+ ```
+
+4. Build using CMake.
+
+You may refer to CI scripts for more details.
+
+## License
+
+DiffScope is licensed under the Apache License, Version 2.0.
+
+This license does not apply to plugins and other third-party dependencies.
+
+Please refer to the plugin directories to view the licenses applicable to each individual plugin.
diff --git a/crowdin.yml b/crowdin.yml
index 14e32c6a..fb4fe0da 100644
--- a/crowdin.yml
+++ b/crowdin.yml
@@ -1,13 +1,3 @@
files:
- - source: /src/plugins/coreplugin/res/translations/Core_en_US.ts
- translation: /src/plugins/coreplugin/res/translations/Core_%locale_with_underscore%.ts
- - source: /src/plugins/audio/res/translations/org.diffscope.audio_en_US.ts
- translation: /src/plugins/audio/res/translations/org.diffscope.audio_%locale_with_underscore%.ts
- - source: /src/plugins/welcomewizard/res/translations/org.diffscope.welcomewizard_en_US.ts
- translation: /src/plugins/welcomewizard/res/translations/org.diffscope.welcomewizard_%locale_with_underscore%.ts
- - source: /src/plugins/achievement/res/translations/org.diffscope.achievement_en_US.ts
- translation: /src/plugins/achievement/res/translations/org.diffscope.achievement_%locale_with_underscore%.ts
- - source: /src/plugins/maintenance/res/translations/org.diffscope.maintenance_en_US.ts
- translation: /src/plugins/maintenance/res/translations/org.diffscope.maintenance_%locale_with_underscore%.ts
- - source: /src/libs/application/uishell/share/translations/uishell_en_US.ts
- translation: /src/libs/application/uishell/share/translations/uishell_%locale_with_underscore%.ts
+ - source: '/**/translations/*_en_US.ts'
+ translation: '/%original_path%/%file_name%_%locale_with_underscore%.ts'
diff --git a/scripts/ci/Build.ps1 b/scripts/ci/Build.ps1
index d7bee6de..0afa4394 100644
--- a/scripts/ci/Build.ps1
+++ b/scripts/ci/Build.ps1
@@ -78,6 +78,8 @@ Write-Host "Semver: $semver"
$installerFileBase = "${applicationName}_$($semver -replace '[\.\-\+]', '_')_installer"
+$depsDir = (Get-ChildItem -Path $(Join-Path $VcpkgRootDir installed) | Where-Object {$_.Name -ne "vcpkg"})[0].FullName
+
cmake -S . -B $(Resolve-Path $BuildDir) -G Ninja `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
"-DCMAKE_TOOLCHAIN_FILE=$(Join-Path $VcpkgRootDir scripts/buildsystems/vcpkg.cmake)" `
@@ -85,6 +87,8 @@ cmake -S . -B $(Resolve-Path $BuildDir) -G Ninja `
"-DCMAKE_CXX_COMPILER_LAUNCHER=$($CCache ? 'ccache' : '')" `
-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded `
-DCK_ENABLE_CONSOLE:BOOL=FALSE `
+ -DQT_NO_PRIVATE_MODULE_WARNING:BOOL=ON `
+ "-DQMSETUP_APPLOCAL_DEPS_PATHS_RELWITHDEBINFO=$(Join-Path $depsDir lib)" `
-DAPPLICATION_INSTALL:BOOL=ON `
-DAPPLICATION_CONFIGURE_INSTALLER:BOOL=ON `
-DINNOSETUP_USE_UNOFFICIAL_LANGUAGE:BOOL=ON `
diff --git a/scripts/ci/Collect-Symbol-Files.ps1 b/scripts/ci/Collect-Symbol-Files.ps1
index 5c4e9206..914b3c52 100644
--- a/scripts/ci/Collect-Symbol-Files.ps1
+++ b/scripts/ci/Collect-Symbol-Files.ps1
@@ -47,6 +47,7 @@ if ($IsWindows) {
}
dsymutil $dllFile.FullName -o "$pdbTargetDirectory/$($dllFile.Name).dSYM"
strip -S $dllFile.FullName
+ codesign --force --sign - $dllFile.FullName
} else {
Write-Host "Skip: $dllFile"
}
diff --git a/scripts/ci/Create-DMG.ps1 b/scripts/ci/Create-DMG.ps1
index f46f57d3..42831d34 100644
--- a/scripts/ci/Create-DMG.ps1
+++ b/scripts/ci/Create-DMG.ps1
@@ -16,6 +16,7 @@ $BackgroundSrcDir = "src/app/share/dmg"
$Bg1x = Join-Path $BackgroundSrcDir "dmg_background.png"
$Bg2x = Join-Path $BackgroundSrcDir "dmg_background@2x.png"
+$Font = Join-Path $BackgroundSrcDir "noto-sans.ttf"
if (!(Test-Path $Bg1x) -or !(Test-Path $Bg2x)) {
throw "dmg_background.png and dmg_background@2x.png do not exist in $BackgroundSrcDir"
@@ -32,6 +33,8 @@ New-Item -ItemType Directory -Path $TempDir | Out-Null
$Bg1xOut = Join-Path $TempDir "dmg_background.png"
$Bg2xOut = Join-Path $TempDir "dmg_background@2x.png"
$BgTiff = Join-Path $TempDir "dmg_background.tiff"
+$AppBundleName = "$ApplicationDisplayName.app"
+$AppBundlePath = Join-Path $TempDir $AppBundleName
$VersionText = "Version $Semver"
@@ -44,6 +47,7 @@ try {
& magick `
"$Bg1x" `
-gravity south `
+ -font $Font `
-pointsize 12 `
-fill "rgba(37,37,37,0.25)" `
-annotate +0+8 "$VersionText" `
@@ -57,6 +61,7 @@ try {
& magick `
"$Bg2x" `
-gravity south `
+ -font $Font `
-pointsize 24 `
-fill "rgba(37,37,37,0.25)" `
-annotate +0+16 "$VersionText" `
@@ -87,16 +92,24 @@ try {
Remove-Item $DmgPath -Force
}
+ if (Test-Path $AppBundlePath) {
+ Remove-Item $AppBundlePath -Recurse -Force
+ }
+
+ Move-Item -Path $AppPath -Destination $AppBundlePath
+
+ & codesign --deep --force --sign - $AppBundlePath | Write-Host
+
<# TODO: create-dmg currently places hidden .background file to the right of the visible area, so we have to leave some space for the horizontal scroll bar #>
& create-dmg `
--volname "$ApplicationDisplayName" `
--background "$BgTiff" `
--window-size 600 448 `
--icon-size 128 `
- --icon "$(Split-Path $AppPath -Leaf)" 132 280 `
+ --icon "$(Split-Path $AppBundlePath -Leaf)" 132 280 `
--app-drop-link 468 280 `
"$DmgPath" `
- "$AppPath" | Write-Host
+ "$AppBundlePath" | Write-Host
if ($LASTEXITCODE -ne 0) {
throw "create-dmg failed"
diff --git a/scripts/vcpkg b/scripts/vcpkg
index 5e0443fe..bd263bcf 160000
--- a/scripts/vcpkg
+++ b/scripts/vcpkg
@@ -1 +1 @@
-Subproject commit 5e0443fea12ce12f165fb16d7546b20a64894615
+Subproject commit bd263bcfe9345673d6ee81d134c7459095541aa8
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 4264e630..d95d1d65 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -29,6 +29,7 @@ endif()
ck_configure_application(
${_ico_args}
${_icns_args}
+ INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/info.plist.in
)
qm_configure_target(${PROJECT_NAME}
@@ -70,6 +71,12 @@ ck_add_shared_files(
# SRC conf/${CK_PLATFORM_LOWER}/qtmediate.json DEST ${CK_BUILD_QT_CONF_DIR} # qtmediate.json
)
+if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/icons/dspx.icns)
+ ck_add_shared_files(
+ SRC ${CMAKE_CURRENT_BINARY_DIR}/icons/dspx.icns DEST ${CK_BUILD_DATA_DIR}
+ )
+endif()
+
file(GLOB _icons icons/*)
list(FILTER _icons EXCLUDE REGEX CMakeLists.txt)
diff --git a/src/app/app.icns b/src/app/app.icns
deleted file mode 100644
index 45ee9f55..00000000
Binary files a/src/app/app.icns and /dev/null differ
diff --git a/src/app/app.ico b/src/app/app.ico
deleted file mode 100644
index ef1b8a8d..00000000
Binary files a/src/app/app.ico and /dev/null differ
diff --git a/src/app/icons/app/1024x1024.png b/src/app/icons/app/1024x1024.png
index 595fa0c1..5cc082ab 100644
Binary files a/src/app/icons/app/1024x1024.png and b/src/app/icons/app/1024x1024.png differ
diff --git a/src/app/icons/app/128x128.png b/src/app/icons/app/128x128.png
index 3bba0816..40002ccf 100644
Binary files a/src/app/icons/app/128x128.png and b/src/app/icons/app/128x128.png differ
diff --git a/src/app/icons/app/16x16.png b/src/app/icons/app/16x16.png
index b76cbccd..8076d8e4 100644
Binary files a/src/app/icons/app/16x16.png and b/src/app/icons/app/16x16.png differ
diff --git a/src/app/icons/app/24x24.png b/src/app/icons/app/24x24.png
index fa072dcf..5034a1e1 100644
Binary files a/src/app/icons/app/24x24.png and b/src/app/icons/app/24x24.png differ
diff --git a/src/app/icons/app/256x256.png b/src/app/icons/app/256x256.png
index 2863a6b8..9a1e818a 100644
Binary files a/src/app/icons/app/256x256.png and b/src/app/icons/app/256x256.png differ
diff --git a/src/app/icons/app/32x32.png b/src/app/icons/app/32x32.png
index d2b12c3a..50a25833 100644
Binary files a/src/app/icons/app/32x32.png and b/src/app/icons/app/32x32.png differ
diff --git a/src/app/icons/app/48x48.png b/src/app/icons/app/48x48.png
index 0ef539b2..d9c210d5 100644
Binary files a/src/app/icons/app/48x48.png and b/src/app/icons/app/48x48.png differ
diff --git a/src/app/icons/app/512x512.png b/src/app/icons/app/512x512.png
index 31de1904..171647d0 100644
Binary files a/src/app/icons/app/512x512.png and b/src/app/icons/app/512x512.png differ
diff --git a/src/app/icons/app/64x64.png b/src/app/icons/app/64x64.png
index 2edd60d2..9e2f5065 100644
Binary files a/src/app/icons/app/64x64.png and b/src/app/icons/app/64x64.png differ
diff --git a/src/app/icons/app/96x96.png b/src/app/icons/app/96x96.png
index 582d173c..f3aa1160 100644
Binary files a/src/app/icons/app/96x96.png and b/src/app/icons/app/96x96.png differ
diff --git a/src/app/icons/dspx/1024x1024.png b/src/app/icons/dspx/1024x1024.png
index ab728062..15d1bbf1 100644
Binary files a/src/app/icons/dspx/1024x1024.png and b/src/app/icons/dspx/1024x1024.png differ
diff --git a/src/app/icons/dspx/128x128.png b/src/app/icons/dspx/128x128.png
index c46ab436..9dded4b9 100644
Binary files a/src/app/icons/dspx/128x128.png and b/src/app/icons/dspx/128x128.png differ
diff --git a/src/app/icons/dspx/16x16.png b/src/app/icons/dspx/16x16.png
index c2d9766e..b6d000e9 100644
Binary files a/src/app/icons/dspx/16x16.png and b/src/app/icons/dspx/16x16.png differ
diff --git a/src/app/icons/dspx/24x24.png b/src/app/icons/dspx/24x24.png
index 5ec9dd19..e41e08bb 100644
Binary files a/src/app/icons/dspx/24x24.png and b/src/app/icons/dspx/24x24.png differ
diff --git a/src/app/icons/dspx/256x256.png b/src/app/icons/dspx/256x256.png
index 697df2f4..288b77ca 100644
Binary files a/src/app/icons/dspx/256x256.png and b/src/app/icons/dspx/256x256.png differ
diff --git a/src/app/icons/dspx/32x32.png b/src/app/icons/dspx/32x32.png
index 4067e408..c12d74e3 100644
Binary files a/src/app/icons/dspx/32x32.png and b/src/app/icons/dspx/32x32.png differ
diff --git a/src/app/icons/dspx/48x48.png b/src/app/icons/dspx/48x48.png
index 6a448b74..daef6b5c 100644
Binary files a/src/app/icons/dspx/48x48.png and b/src/app/icons/dspx/48x48.png differ
diff --git a/src/app/icons/dspx/512x512.png b/src/app/icons/dspx/512x512.png
index c089956e..6a42dc64 100644
Binary files a/src/app/icons/dspx/512x512.png and b/src/app/icons/dspx/512x512.png differ
diff --git a/src/app/icons/dspx/64x64.png b/src/app/icons/dspx/64x64.png
index 0eacabf4..2964871f 100644
Binary files a/src/app/icons/dspx/64x64.png and b/src/app/icons/dspx/64x64.png differ
diff --git a/src/app/icons/dspx/96x96.png b/src/app/icons/dspx/96x96.png
index b286962b..e2c851a8 100644
Binary files a/src/app/icons/dspx/96x96.png and b/src/app/icons/dspx/96x96.png differ
diff --git a/src/app/info.plist.in b/src/app/info.plist.in
new file mode 100644
index 00000000..c10a6e46
--- /dev/null
+++ b/src/app/info.plist.in
@@ -0,0 +1,92 @@
+
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+
+ CFBundleExecutable
+ @APPLICATION_NAME@
+
+ CFBundleIconFile
+ app.icns
+
+ CFBundleIdentifier
+ @APPLICATION_NAME@
+
+ CFBundleInfoDictionaryVersion
+ 6.0
+
+ CFBundleName
+ @APPLICATION_DISPLAY_NAME@
+
+ CFBundlePackageType
+ APPL
+
+ CFBundleShortVersionString
+ @APPLICATION_SEMVER@
+
+ CFBundleSignature
+ ????
+
+ CFBundleVersion
+ @APPLICATION_SEMVER@
+
+ CSResourcesFileMapped
+
+
+ NSHumanReadableCopyright
+ @RC_COPYRIGHT@
+
+ UTExportedTypeDeclarations
+
+
+ UTTypeIdentifier
+ org.diffscope.dspx
+
+ UTTypeDescription
+ DiffScope Project Exchange Format
+
+ UTTypeConformsTo
+
+ public.json
+
+
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ dspx
+
+
+ public.mime-type
+ application/vnd.openvpi.dspx+json
+
+
+
+
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeName
+ DiffScope Project File
+
+ CFBundleTypeRole
+ Editor
+
+ LSItemContentTypes
+
+ org.diffscope.dspx
+
+
+ CFBundleTypeIconFile
+ dspx.icns
+
+ LSHandlerRank
+ Default
+
+
+
+
+
diff --git a/src/app/main.cpp b/src/app/main.cpp
index b1b4c6f8..ee7fe48a 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -17,6 +18,9 @@
#include
#include
+#include
+#include
+
#include
#include
@@ -26,6 +30,8 @@
#include
#include
+#include
+
#ifdef APPLICATION_ENABLE_BREAKPAD
# include
#endif
@@ -39,6 +45,8 @@ static QSettings::Format getJsonSettingsFormat() {
static QQmlEngine *engine{};
+static constexpr char kNoWarningLastInitialization[] = "--no-warning-last-initialization";
+
class MyLoaderSpec : public Loader::LoaderSpec {
public:
MyLoaderSpec() {
@@ -55,6 +63,11 @@ class MyLoaderSpec : public Loader::LoaderSpec {
QStringLiteral("/config.json");
pluginPaths << ApplicationInfo::applicationLocation(ApplicationInfo::BuiltinPlugins);
coreName = QStringLiteral("org.diffscope.core");
+ extraArguments << Argument{
+ {kNoWarningLastInitialization},
+ {},
+ QStringLiteral("Suppress warning about 'Last initialization was aborted abnormally'")
+ };
}
QSettings *createExtensionSystemSettings(QSettings::Scope scope) override {
@@ -102,11 +115,25 @@ class MyLoaderSpec : public Loader::LoaderSpec {
locale.setNumberOptions(QLocale::OmitGroupSeparator);
RuntimeInterface::setTranslationManager(new TranslationManager(RuntimeInterface::instance()));
RuntimeInterface::translationManager()->setLocale(locale);
- RuntimeInterface::translationManager()->addTranslationPath(ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/ChorusKit/translations"));
- RuntimeInterface::translationManager()->addTranslationPath(ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/svscraft/translations"));
- RuntimeInterface::translationManager()->addTranslationPath(ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/uishell/translations"));
+ auto translationBaseDir =
+#ifdef Q_OS_MAC
+ ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/share");
+#else
+ ApplicationInfo::systemLocation(ApplicationInfo::Resources);
+#endif
+ RuntimeInterface::translationManager()->addTranslationPath(translationBaseDir + QStringLiteral("/ChorusKit/translations"));
+ RuntimeInterface::translationManager()->addTranslationPath(translationBaseDir + QStringLiteral("/svscraft/translations"));
+ RuntimeInterface::translationManager()->addTranslationPath(translationBaseDir + QStringLiteral("/uishell/translations"));
+
+ for (auto pluginSpec : ExtensionSystem::PluginManager::plugins()) {
+ static QRegularExpression rx("^([a-z_][a-z0-9_]*)(\\.[a-z_][a-z0-9_]*)+$");
+ if (!rx.match(pluginSpec->name()).hasMatch()) {
+ qFatal() << "Refused to load due to an invalid plugin name:" << pluginSpec->name() << "Plugin name should match" << rx.pattern();
+ }
+ }
- if (settings->value("lastInitializationAbortedFlag").toBool()) {
+ bool lastInitializationWarningSuppressed = QApplication::arguments().contains(kNoWarningLastInitialization);
+ if (settings->value("lastInitializationAbortedFlag").toBool() && !lastInitializationWarningSuppressed) {
qInfo() << "Last initialization was aborted abnormally";
QQmlComponent component(engine, "DiffScope.UIShell", "InitializationFailureWarningDialog");
std::unique_ptr dialog(component.isError() ? nullptr : component.createWithInitialProperties({
@@ -182,5 +209,13 @@ int main(int argc, char *argv[]) {
QQuickStyle::setFallbackStyle("Basic");
QApplication::setStyle(QStyleFactory::create("Fusion"));
+ // Check QML import
+ {
+ QQmlComponent component(engine, "DiffScope.UIShell", "ProjectWindow");
+ if (component.isError()) {
+ qFatal().nospace() << "QML Import Check Failed: " << component.errorString() << "\n\n" << "Note for developers: If you encounter this error when running after building DiffScope, please check:\n- Whether all targets have been built\n- Whether the correct QML_IMPORT_PATH environment variable was specified at runtime (it may need to be set to `../qml`)";
+ }
+ }
+
return MyLoaderSpec().run();
}
diff --git a/src/app/share/dmg/dmg_background.png b/src/app/share/dmg/dmg_background.png
index 56a7dd80..b24f6e43 100644
Binary files a/src/app/share/dmg/dmg_background.png and b/src/app/share/dmg/dmg_background.png differ
diff --git a/src/app/share/dmg/dmg_background@2x.png b/src/app/share/dmg/dmg_background@2x.png
index 0f3a01fc..826aa1b0 100644
Binary files a/src/app/share/dmg/dmg_background@2x.png and b/src/app/share/dmg/dmg_background@2x.png differ
diff --git a/src/app/share/dmg/noto-sans.ttf b/src/app/share/dmg/noto-sans.ttf
new file mode 100644
index 00000000..7c9a248a
Binary files /dev/null and b/src/app/share/dmg/noto-sans.ttf differ
diff --git a/src/app/splash.png b/src/app/splash.png
index af7f8525..dbda4b56 100644
Binary files a/src/app/splash.png and b/src/app/splash.png differ
diff --git a/src/libs/3rdparty/choruskit b/src/libs/3rdparty/choruskit
index ead08258..a138c114 160000
--- a/src/libs/3rdparty/choruskit
+++ b/src/libs/3rdparty/choruskit
@@ -1 +1 @@
-Subproject commit ead082581b7116763a27e29f733fa13e4edb963b
+Subproject commit a138c114a401836955c6b90c389ad440a826a668
diff --git a/src/libs/3rdparty/opendspx b/src/libs/3rdparty/opendspx
index 0a4bb52e..3d9cd2cf 160000
--- a/src/libs/3rdparty/opendspx
+++ b/src/libs/3rdparty/opendspx
@@ -1 +1 @@
-Subproject commit 0a4bb52e0f199d74d288eda2c9c41bfe2d34d80d
+Subproject commit 3d9cd2cf10916a2bb1f36907d9aad5529b1480ee
diff --git a/src/libs/3rdparty/qactionkit b/src/libs/3rdparty/qactionkit
index 42b9cd90..573def48 160000
--- a/src/libs/3rdparty/qactionkit
+++ b/src/libs/3rdparty/qactionkit
@@ -1 +1 @@
-Subproject commit 42b9cd9053d76aeb8d66728a650827d97f40f11a
+Subproject commit 573def486e3f8c0f62768bcdcbc490b24cbd59af
diff --git a/src/libs/3rdparty/scopicflow b/src/libs/3rdparty/scopicflow
index 06238363..d2cc7ddd 160000
--- a/src/libs/3rdparty/scopicflow
+++ b/src/libs/3rdparty/scopicflow
@@ -1 +1 @@
-Subproject commit 062383639e43b2baa9c3ae20674c8dd153d3a73e
+Subproject commit d2cc7ddd29997d0b0cf1e09d37198f46b4d2bd6a
diff --git a/src/libs/3rdparty/svscraft b/src/libs/3rdparty/svscraft
index 70fab799..12f6d20d 160000
--- a/src/libs/3rdparty/svscraft
+++ b/src/libs/3rdparty/svscraft
@@ -1 +1 @@
-Subproject commit 70fab7997428056a557a82a8e3dce37941c15795
+Subproject commit 12f6d20d0ac66a15661630daf82260c173b1e5f7
diff --git a/src/libs/application/dspxmodel/src/AnchorNode.cpp b/src/libs/application/dspxmodel/src/AnchorNode.cpp
index 22eaba9f..6e65b00d 100644
--- a/src/libs/application/dspxmodel/src/AnchorNode.cpp
+++ b/src/libs/application/dspxmodel/src/AnchorNode.cpp
@@ -1,7 +1,6 @@
#include "AnchorNode.h"
#include "AnchorNode_p.h"
-#include
#include
#include
@@ -12,39 +11,27 @@
namespace dspx {
- void AnchorNodePrivate::setInterpUnchecked(AnchorNode::InterpolationMode interp_) {
- Q_Q(AnchorNode);
- q->model()->strategy()->setEntityProperty(q->handle(), ModelStrategy::P_Type, QVariant::fromValue(interp_));
- }
-
- void AnchorNodePrivate::setInterp(AnchorNode::InterpolationMode interp_) {
- Q_Q(AnchorNode);
- if (auto engine = qjsEngine(q); engine && (interp_ != AnchorNode::None && interp_ != AnchorNode::Linear && interp_ != AnchorNode::Hermite)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Interpolation mode must be one of None, Linear, or Hermite"));
- return;
+ void AnchorNodePrivate::setAnchorNodeSequence(AnchorNode *item, AnchorNodeSequence *anchorNodeSequence) {
+ auto d = item->d_func();
+ if (d->anchorNodeSequence != anchorNodeSequence) {
+ d->anchorNodeSequence = anchorNodeSequence;
+ Q_EMIT item->anchorNodeSequenceChanged();
}
- setInterpUnchecked(interp_);
}
- void AnchorNodePrivate::setXUnchecked(int x_) {
- Q_Q(AnchorNode);
- q->model()->strategy()->setEntityProperty(q->handle(), ModelStrategy::P_Position, x_);
- }
-
- void AnchorNodePrivate::setX(int x_) {
- Q_Q(AnchorNode);
- if (auto engine = qjsEngine(q); engine && x_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Position must be greater or equal to 0"));
- return;
+ void AnchorNodePrivate::setPreviousItem(AnchorNode *item, AnchorNode *previousItem) {
+ auto d = item->d_func();
+ if (d->previousItem != previousItem) {
+ d->previousItem = previousItem;
+ Q_EMIT item->previousItemChanged();
}
- setXUnchecked(x_);
}
- void AnchorNodePrivate::setAnchorNodeSequence(AnchorNode *item, AnchorNodeSequence *anchorNodeSequence) {
+ void AnchorNodePrivate::setNextItem(AnchorNode *item, AnchorNode *nextItem) {
auto d = item->d_func();
- if (d->anchorNodeSequence != anchorNodeSequence) {
- d->anchorNodeSequence = anchorNodeSequence;
- Q_EMIT item->anchorNodeSequenceChanged();
+ if (d->nextItem != nextItem) {
+ d->nextItem = nextItem;
+ Q_EMIT item->nextItemChanged();
}
}
@@ -68,7 +55,7 @@ namespace dspx {
void AnchorNode::setInterp(InterpolationMode interp) {
Q_D(AnchorNode);
Q_ASSERT(interp == None || interp == Linear || interp == Hermite);
- d->setInterpUnchecked(interp);
+ model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Type, QVariant::fromValue(interp));
}
int AnchorNode::x() const {
@@ -79,7 +66,7 @@ namespace dspx {
void AnchorNode::setX(int x) {
Q_D(AnchorNode);
Q_ASSERT(x >= 0);
- d->setXUnchecked(x);
+ model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Position, x);
}
int AnchorNode::y() const {
@@ -92,16 +79,16 @@ namespace dspx {
model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Value, y);
}
- QDspx::AnchorNode AnchorNode::toQDspx() const {
+ opendspx::AnchorNode AnchorNode::toOpenDspx() const {
Q_D(const AnchorNode);
return {
- .interp = static_cast(d->interp),
+ .interp = static_cast(d->interp),
.x = d->x,
.y = d->y,
};
}
- void AnchorNode::fromQDspx(const QDspx::AnchorNode &node) {
+ void AnchorNode::fromOpenDspx(const opendspx::AnchorNode &node) {
Q_D(AnchorNode);
setInterp(static_cast(node.interp));
setX(node.x);
@@ -113,6 +100,16 @@ namespace dspx {
return d->anchorNodeSequence;
}
+ AnchorNode *AnchorNode::previousItem() const {
+ Q_D(const AnchorNode);
+ return d->previousItem;
+ }
+
+ AnchorNode *AnchorNode::nextItem() const {
+ Q_D(const AnchorNode);
+ return d->nextItem;
+ }
+
void AnchorNode::handleSetEntityProperty(int property, const QVariant &value) {
Q_D(AnchorNode);
switch (property) {
diff --git a/src/libs/application/dspxmodel/src/AnchorNode.h b/src/libs/application/dspxmodel/src/AnchorNode.h
index 4eaef0e8..85dc1f85 100644
--- a/src/libs/application/dspxmodel/src/AnchorNode.h
+++ b/src/libs/application/dspxmodel/src/AnchorNode.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct AnchorNode;
}
@@ -22,10 +22,12 @@ namespace dspx {
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(AnchorNode)
- Q_PRIVATE_PROPERTY(d_func(), InterpolationMode interp MEMBER interp WRITE setInterp NOTIFY interpChanged)
- Q_PRIVATE_PROPERTY(d_func(), int x MEMBER x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(InterpolationMode interp READ interp WRITE setInterp NOTIFY interpChanged)
+ Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged)
Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged)
Q_PROPERTY(AnchorNodeSequence *anchorNodeSequence READ anchorNodeSequence NOTIFY anchorNodeSequenceChanged)
+ Q_PROPERTY(AnchorNode *previousItem READ previousItem NOTIFY previousItemChanged)
+ Q_PROPERTY(AnchorNode *nextItem READ nextItem NOTIFY nextItemChanged)
public:
enum InterpolationMode {
@@ -46,16 +48,20 @@ namespace dspx {
int y() const;
void setY(int y);
- QDspx::AnchorNode toQDspx() const;
- void fromQDspx(const QDspx::AnchorNode &node);
+ opendspx::AnchorNode toOpenDspx() const;
+ void fromOpenDspx(const opendspx::AnchorNode &node);
AnchorNodeSequence *anchorNodeSequence() const;
+ AnchorNode *previousItem() const;
+ AnchorNode *nextItem() const;
Q_SIGNALS:
void interpChanged(InterpolationMode interp);
void xChanged(int x);
void yChanged(int y);
void anchorNodeSequenceChanged();
+ void previousItemChanged();
+ void nextItemChanged();
protected:
void handleSetEntityProperty(int property, const QVariant &value) override;
diff --git a/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp b/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp
index 2d6e9d87..461d0688 100644
--- a/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp
+++ b/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp
@@ -22,13 +22,6 @@ namespace dspx {
d->paramCurveAnchor = paramCurveAnchor;
d->init(model->strategy()->getEntitiesFromSequenceContainer(handle));
-
- connect(this, &AnchorNodeSequence::itemInserted, this, [=](AnchorNode *item) {
- AnchorNodePrivate::setAnchorNodeSequence(item, this);
- });
- connect(this, &AnchorNodeSequence::itemRemoved, this, [=](AnchorNode *item) {
- AnchorNodePrivate::setAnchorNodeSequence(item, nullptr);
- });
}
AnchorNodeSequence::~AnchorNodeSequence() = default;
@@ -78,23 +71,23 @@ namespace dspx {
return d->pModel->strategy->takeFromSequenceContainer(handle(), item->handle());
}
- QList AnchorNodeSequence::toQDspx() const {
+ std::vector AnchorNodeSequence::toOpenDspx() const {
Q_D(const AnchorNodeSequence);
- QList ret;
+ std::vector ret;
ret.reserve(d->container.size());
for (const auto &[_, item] : d->container.m_items) {
- ret.append(item->toQDspx());
+ ret.push_back(item->toOpenDspx());
}
return ret;
}
- void AnchorNodeSequence::fromQDspx(const QList &nodes) {
+ void AnchorNodeSequence::fromOpenDspx(const std::vector &nodes) {
while (size()) {
removeItem(firstItem());
}
for (const auto &node : nodes) {
auto item = model()->createAnchorNode();
- item->fromQDspx(node);
+ item->fromOpenDspx(node);
insertItem(item);
}
}
diff --git a/src/libs/application/dspxmodel/src/AnchorNodeSequence.h b/src/libs/application/dspxmodel/src/AnchorNodeSequence.h
index a965ba5f..4748fccc 100644
--- a/src/libs/application/dspxmodel/src/AnchorNodeSequence.h
+++ b/src/libs/application/dspxmodel/src/AnchorNodeSequence.h
@@ -6,7 +6,7 @@
#include
#include
-namespace QDspx {
+namespace opendspx {
struct AnchorNode;
}
@@ -41,8 +41,8 @@ namespace dspx {
Q_INVOKABLE bool insertItem(AnchorNode *item);
Q_INVOKABLE bool removeItem(AnchorNode *item);
- QList toQDspx() const;
- void fromQDspx(const QList &nodes);
+ std::vector toOpenDspx() const;
+ void fromOpenDspx(const std::vector &nodes);
ParamCurveAnchor *paramCurveAnchor() const;
diff --git a/src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h b/src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h
index 8b27bf67..24cb0f23 100644
--- a/src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h
+++ b/src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h
@@ -8,7 +8,14 @@
namespace dspx {
- class AnchorNodeSequencePrivate : public PointSequenceData {
+ class AnchorNodeSequencePrivate : public PointSequenceData<
+ AnchorNodeSequence,
+ AnchorNode,
+ &AnchorNode::x,
+ &AnchorNode::xChanged,
+ &AnchorNodePrivate::setAnchorNodeSequence,
+ &AnchorNodePrivate::setPreviousItem,
+ &AnchorNodePrivate::setNextItem> {
Q_DECLARE_PUBLIC(AnchorNodeSequence)
public:
ParamCurveAnchor *paramCurveAnchor{};
diff --git a/src/libs/application/dspxmodel/src/AnchorNode_p.h b/src/libs/application/dspxmodel/src/AnchorNode_p.h
index 3b2704b6..ec8af70a 100644
--- a/src/libs/application/dspxmodel/src/AnchorNode_p.h
+++ b/src/libs/application/dspxmodel/src/AnchorNode_p.h
@@ -13,13 +13,12 @@ namespace dspx {
int x;
int y;
AnchorNodeSequence *anchorNodeSequence{};
-
- void setInterpUnchecked(AnchorNode::InterpolationMode interp_);
- void setInterp(AnchorNode::InterpolationMode interp_);
- void setXUnchecked(int x_);
- void setX(int x_);
+ AnchorNode *previousItem{};
+ AnchorNode *nextItem{};
static void setAnchorNodeSequence(AnchorNode *item, AnchorNodeSequence *anchorNodeSequence);
+ static void setPreviousItem(AnchorNode *item, AnchorNode *previousItem);
+ static void setNextItem(AnchorNode *item, AnchorNode *nextItem);
};
}
diff --git a/src/libs/application/dspxmodel/src/AudioClip.cpp b/src/libs/application/dspxmodel/src/AudioClip.cpp
index 72a6d736..cdc34128 100644
--- a/src/libs/application/dspxmodel/src/AudioClip.cpp
+++ b/src/libs/application/dspxmodel/src/AudioClip.cpp
@@ -37,22 +37,22 @@ namespace dspx {
d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_Path, path);
}
- QDspx::AudioClip AudioClip::toQDspx() const {
+ opendspx::AudioClip AudioClip::toOpenDspx() const {
return {
- name(),
- control()->toQDspx(),
- time()->toQDspx(),
- workspace()->toQDspx(),
- path()
+ name().toStdString(),
+ control()->toOpenDspx(),
+ time()->toOpenDspx(),
+ workspace()->toOpenDspx(),
+ path().toStdString()
};
}
- void AudioClip::fromQDspx(const QDspx::AudioClip &clip) {
- setName(clip.name);
- control()->fromQDspx(clip.control);
- time()->fromQDspx(clip.time);
- workspace()->fromQDspx(clip.workspace);
- setPath(clip.path);
+ void AudioClip::fromOpenDspx(const opendspx::AudioClip &clip) {
+ setName(QString::fromStdString(clip.name));
+ control()->fromOpenDspx(clip.control);
+ time()->fromOpenDspx(clip.time);
+ workspace()->fromOpenDspx(clip.workspace);
+ setPath(QString::fromStdString(clip.path));
}
void AudioClip::handleSetEntityProperty(int property, const QVariant &value) {
diff --git a/src/libs/application/dspxmodel/src/AudioClip.h b/src/libs/application/dspxmodel/src/AudioClip.h
index 3c8db6cc..027f1646 100644
--- a/src/libs/application/dspxmodel/src/AudioClip.h
+++ b/src/libs/application/dspxmodel/src/AudioClip.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct AudioClip;
}
@@ -26,8 +26,8 @@ namespace dspx {
QString path() const;
void setPath(const QString &path);
- QDspx::AudioClip toQDspx() const;
- void fromQDspx(const QDspx::AudioClip &clip);
+ opendspx::AudioClip toOpenDspx() const;
+ void fromOpenDspx(const opendspx::AudioClip &clip);
Q_SIGNALS:
void pathChanged(const QString &path);
diff --git a/src/libs/application/dspxmodel/src/BasicModelStrategy.cpp b/src/libs/application/dspxmodel/src/BasicModelStrategy.cpp
index 0e6e8a67..a88d80df 100644
--- a/src/libs/application/dspxmodel/src/BasicModelStrategy.cpp
+++ b/src/libs/application/dspxmodel/src/BasicModelStrategy.cpp
@@ -96,6 +96,20 @@ namespace dspx {
return true;
}
+ bool BasicModelStrategy::moveToAnotherSequenceContainer(Handle sequenceContainerEntity, Handle entity, Handle otherSequenceContainerEntity) {
+ auto sequenceContainerObject = handleCast(sequenceContainerEntity);
+ auto otherSequenceContainerObject = handleCast(otherSequenceContainerEntity);
+ auto object = reinterpret_cast(entity.d);
+ if (!sequenceContainerObject->sequence.contains(object)) {
+ return false;
+ }
+ sequenceContainerObject->sequence.remove(object);
+ otherSequenceContainerObject->sequence.insert(object);
+ object->setParent(otherSequenceContainerObject);
+ Q_EMIT moveToAnotherSequenceContainerNotified(sequenceContainerEntity, entity, otherSequenceContainerEntity);
+ return true;
+ }
+
Handle BasicModelStrategy::takeFromSequenceContainer(Handle sequenceContainerEntity, Handle entity) {
auto sequenceContainerObject = handleCast(sequenceContainerEntity);
auto object = reinterpret_cast(entity.d);
diff --git a/src/libs/application/dspxmodel/src/BasicModelStrategy.h b/src/libs/application/dspxmodel/src/BasicModelStrategy.h
index 9f638397..0cf44804 100644
--- a/src/libs/application/dspxmodel/src/BasicModelStrategy.h
+++ b/src/libs/application/dspxmodel/src/BasicModelStrategy.h
@@ -20,6 +20,7 @@ namespace dspx {
bool insertIntoSequenceContainer(Handle sequenceContainerEntity, Handle entity) override;
bool insertIntoListContainer(Handle listContainerEntity, Handle entity, int index) override;
bool insertIntoMapContainer(Handle mapContainerEntity, Handle entity, const QString &key) override;
+ bool moveToAnotherSequenceContainer(Handle sequenceContainerEntity, Handle entity, Handle otherSequenceContainerEntity) override;
Handle takeFromSequenceContainer(Handle sequenceContainerEntity, Handle entity) override;
Handle takeFromListContainer(Handle listContainerEntity, int index) override;
Handle takeFromMapContainer(Handle mapContainerEntity, const QString &key) override;
diff --git a/src/libs/application/dspxmodel/src/BasicModelStrategyEntity_p.h b/src/libs/application/dspxmodel/src/BasicModelStrategyEntity_p.h
index 8b111d48..1dcf7555 100644
--- a/src/libs/application/dspxmodel/src/BasicModelStrategyEntity_p.h
+++ b/src/libs/application/dspxmodel/src/BasicModelStrategyEntity_p.h
@@ -64,6 +64,7 @@ namespace dspx {
switch (type) {
case ModelStrategy::EI_AudioClip:
case ModelStrategy::EI_Global:
+ case ModelStrategy::EI_KeySignature:
case ModelStrategy::EI_Label:
case ModelStrategy::EI_Note:
case ModelStrategy::EI_Param:
@@ -81,16 +82,17 @@ namespace dspx {
obj->type = type;
break;
case ModelStrategy::ES_Clips:
+ case ModelStrategy::ES_KeySignatures:
case ModelStrategy::ES_Labels:
case ModelStrategy::ES_Notes:
case ModelStrategy::ES_ParamCurveAnchorNodes:
case ModelStrategy::ES_ParamCurves:
+ case ModelStrategy::ES_Phonemes:
case ModelStrategy::ES_Tempos:
case ModelStrategy::ES_TimeSignatures:
obj = new BasicModelStrategySequenceContainerEntity(parent);
obj->type = type;
break;
- case ModelStrategy::EL_Phonemes:
case ModelStrategy::EL_Tracks:
obj = new BasicModelStrategyListContainerEntity(parent);
obj->type = type;
diff --git a/src/libs/application/dspxmodel/src/BusControl.cpp b/src/libs/application/dspxmodel/src/BusControl.cpp
index ee5d174a..e46599ee 100644
--- a/src/libs/application/dspxmodel/src/BusControl.cpp
+++ b/src/libs/application/dspxmodel/src/BusControl.cpp
@@ -2,6 +2,8 @@
#include
+#include
+
namespace dspx {
BusControl::BusControl(Handle handle, Model *model) : Control(handle, model) {
@@ -9,16 +11,16 @@ namespace dspx {
BusControl::~BusControl() = default;
- QDspx::BusControl BusControl::toQDspx() const {
+ opendspx::BusControl BusControl::toOpenDspx() const {
return {
- .gain = gain(),
+ .gain = SVS::DecibelLinearizer::gainToDecibels(gain()),
.pan = pan(),
.mute = mute()
};
}
- void BusControl::fromQDspx(const QDspx::BusControl &control) {
- setGain(control.gain);
+ void BusControl::fromOpenDspx(const opendspx::BusControl &control) {
+ setGain(SVS::DecibelLinearizer::decibelsToGain(control.gain));
setPan(control.pan);
setMute(control.mute);
}
diff --git a/src/libs/application/dspxmodel/src/BusControl.h b/src/libs/application/dspxmodel/src/BusControl.h
index b395f809..1a670911 100644
--- a/src/libs/application/dspxmodel/src/BusControl.h
+++ b/src/libs/application/dspxmodel/src/BusControl.h
@@ -3,7 +3,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct BusControl;
}
@@ -17,8 +17,8 @@ namespace dspx {
public:
~BusControl() override;
- QDspx::BusControl toQDspx() const;
- void fromQDspx(const QDspx::BusControl &control);
+ opendspx::BusControl toOpenDspx() const;
+ void fromOpenDspx(const opendspx::BusControl &control);
private:
friend class ModelPrivate;
diff --git a/src/libs/application/dspxmodel/src/CMakeLists.txt b/src/libs/application/dspxmodel/src/CMakeLists.txt
index 66c13391..6bececcf 100644
--- a/src/libs/application/dspxmodel/src/CMakeLists.txt
+++ b/src/libs/application/dspxmodel/src/CMakeLists.txt
@@ -15,6 +15,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC
qm_configure_target(${PROJECT_NAME}
SOURCES ${_src}
LINKS opendspx::model
+ LINKS_PRIVATE svscraft::Core
QT_LINKS Core Gui Qml
QT_INCLUDE_PRIVATE Core Gui Qml
INCLUDE_PRIVATE *
diff --git a/src/libs/application/dspxmodel/src/Clip.cpp b/src/libs/application/dspxmodel/src/Clip.cpp
index 4caf4492..90279b25 100644
--- a/src/libs/application/dspxmodel/src/Clip.cpp
+++ b/src/libs/application/dspxmodel/src/Clip.cpp
@@ -32,6 +32,22 @@ namespace dspx {
}
}
+ void ClipPrivate::setPreviousItem(Clip *item, Clip *previousItem) {
+ auto d = item->d_func();
+ if (d->previousItem != previousItem) {
+ d->previousItem = previousItem;
+ Q_EMIT item->previousItemChanged();
+ }
+ }
+
+ void ClipPrivate::setNextItem(Clip *item, Clip *nextItem) {
+ auto d = item->d_func();
+ if (d->nextItem != nextItem) {
+ d->nextItem = nextItem;
+ Q_EMIT item->nextItemChanged();
+ }
+ }
+
Clip::Clip(ClipType type, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ClipPrivate) {
Q_D(Clip);
d->q_ptr = this;
@@ -85,25 +101,25 @@ namespace dspx {
return d->workspace;
}
- QDspx::ClipRef Clip::toQDspx() const {
+ opendspx::ClipRef Clip::toOpenDspx() const {
Q_D(const Clip);
switch (d->type) {
case Audio:
- return QSharedPointer::create(static_cast(this)->toQDspx());
+ return std::make_shared(static_cast(this)->toOpenDspx());
case Singing:
- return QSharedPointer::create(static_cast(this)->toQDspx());
+ return std::make_shared(static_cast(this)->toOpenDspx());
default:
Q_UNREACHABLE();
}
}
- void Clip::fromQDspx(const QDspx::ClipRef &clip) {
+ void Clip::fromOpenDspx(const opendspx::ClipRef &clip) {
switch (clip->type) {
- case QDspx::Clip::Audio:
- static_cast(this)->fromQDspx(*clip.staticCast());
+ case opendspx::Clip::Type::Audio:
+ static_cast(this)->fromOpenDspx(*std::static_pointer_cast(clip));
break;
- case QDspx::Clip::Singing:
- static_cast(this)->fromQDspx(*clip.staticCast());
+ case opendspx::Clip::Type::Singing:
+ static_cast(this)->fromOpenDspx(*std::static_pointer_cast(clip));
break;
default:
Q_UNREACHABLE();
@@ -115,6 +131,16 @@ namespace dspx {
return d->clipSequence;
}
+ Clip *Clip::previousItem() const {
+ Q_D(const Clip);
+ return d->previousItem;
+ }
+
+ Clip *Clip::nextItem() const {
+ Q_D(const Clip);
+ return d->nextItem;
+ }
+
int Clip::position() const {
Q_D(const Clip);
return d->time->start() + d->time->clipStart();
diff --git a/src/libs/application/dspxmodel/src/Clip.h b/src/libs/application/dspxmodel/src/Clip.h
index c35024e9..3756e51c 100644
--- a/src/libs/application/dspxmodel/src/Clip.h
+++ b/src/libs/application/dspxmodel/src/Clip.h
@@ -5,9 +5,9 @@
#include
-namespace QDspx {
+namespace opendspx {
struct Clip;
- using ClipRef = QSharedPointer;
+ using ClipRef = std::shared_ptr;
}
namespace dspx {
@@ -30,6 +30,8 @@ namespace dspx {
Q_PROPERTY(ClipType type READ type CONSTANT)
Q_PROPERTY(Workspace *workspace READ workspace CONSTANT)
Q_PROPERTY(ClipSequence *clipSequence READ clipSequence NOTIFY clipSequenceChanged)
+ Q_PROPERTY(Clip *previousItem READ previousItem NOTIFY previousItemChanged)
+ Q_PROPERTY(Clip *nextItem READ nextItem NOTIFY nextItemChanged)
Q_PROPERTY(bool overlapped READ isOverlapped NOTIFY overlappedChanged)
public:
enum ClipType {
@@ -51,11 +53,14 @@ namespace dspx {
Workspace *workspace() const;
- QDspx::ClipRef toQDspx() const;
- void fromQDspx(const QDspx::ClipRef &clip);
+ opendspx::ClipRef toOpenDspx() const;
+ void fromOpenDspx(const opendspx::ClipRef &clip);
ClipSequence *clipSequence() const;
+ Clip *previousItem() const;
+ Clip *nextItem() const;
+
int position() const;
int length() const;
@@ -65,6 +70,8 @@ namespace dspx {
Q_SIGNALS:
void nameChanged(const QString &name);
void clipSequenceChanged();
+ void previousItemChanged();
+ void nextItemChanged();
void positionChanged(int position);
void lengthChanged(int length);
void overlappedChanged(bool overlapped);
diff --git a/src/libs/application/dspxmodel/src/ClipSequence.cpp b/src/libs/application/dspxmodel/src/ClipSequence.cpp
index 93f6a778..36a0907b 100644
--- a/src/libs/application/dspxmodel/src/ClipSequence.cpp
+++ b/src/libs/application/dspxmodel/src/ClipSequence.cpp
@@ -16,6 +16,67 @@
namespace dspx {
+ void ClipSequencePrivate::handleMoveFromAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) {
+ auto q = q_ptr;
+ auto item = getItem(entity, true);
+ if (!pointContainer.contains(item)) {
+ QObject::connect(item, &Clip::positionChanged, q, [=](int pos) {
+ int length = item->length();
+ insertItem(item, pos, length);
+ });
+ QObject::connect(item, &Clip::lengthChanged, q, [=](int len) {
+ int position = item->position();
+ insertItem(item, position, len);
+ });
+ QObject::connect(item, &QObject::destroyed, q, [=] {
+ removeItem(item);
+ });
+ }
+ auto otherClipSequence = qobject_cast(pModel->mapToObject(otherSequenceContainerEntity));
+ bool containsItem = pointContainer.contains(item);
+ if (!containsItem) {
+ Q_EMIT q->itemAboutToInsert(item, otherClipSequence);
+ }
+
+ pointContainer.insertItem(item, item->position());
+ ClipPrivate::setClipSequence(item, q);
+ auto affectedItems = rangeContainer.insertItem(item, item->position(), item->length());
+
+ for (auto affectedItem : affectedItems) {
+ bool isOverlapped = rangeContainer.isOverlapped(affectedItem);
+ ClipPrivate::setOverlapped(affectedItem, isOverlapped);
+ }
+
+ if (!containsItem) {
+ updateFirstAndLastItem();
+ Q_EMIT q->itemInserted(item, otherClipSequence);
+ Q_EMIT q->sizeChanged(pointContainer.size());
+ }
+ }
+
+ void ClipSequencePrivate::handleMoveToAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) {
+ auto q = q_ptr;
+ auto item = getItem(entity, false);
+ if (item) {
+ QObject::disconnect(item, nullptr, q, nullptr);
+ auto otherClipSequence = qobject_cast(pModel->mapToObject(otherSequenceContainerEntity));
+ Q_EMIT q->itemAboutToRemove(item, otherClipSequence);
+
+ pointContainer.removeItem(item);
+ ClipPrivate::setClipSequence(item, otherClipSequence);
+ auto affectedItems = rangeContainer.removeItem(item);
+
+ for (auto affectedItem : affectedItems) {
+ bool isOverlapped = rangeContainer.isOverlapped(affectedItem);
+ ClipPrivate::setOverlapped(affectedItem, isOverlapped);
+ }
+
+ updateFirstAndLastItem();
+ Q_EMIT q->itemRemoved(item, otherClipSequence);
+ Q_EMIT q->sizeChanged(pointContainer.size());
+ }
+ }
+
ClipSequence::ClipSequence(Track *track, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ClipSequencePrivate) {
Q_D(ClipSequence);
Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_Clips);
@@ -24,13 +85,6 @@ namespace dspx {
d->track = track;
d->init(model->strategy()->getEntitiesFromSequenceContainer(handle));
-
- connect(this, &ClipSequence::itemInserted, this, [=](Clip *item) {
- ClipPrivate::setClipSequence(item, this);
- });
- connect(this, &ClipSequence::itemRemoved, this, [=](Clip *item) {
- ClipPrivate::setClipSequence(item, nullptr);
- });
}
ClipSequence::~ClipSequence() = default;
@@ -85,33 +139,38 @@ namespace dspx {
return d->pModel->strategy->takeFromSequenceContainer(handle(), item->handle());
}
- QList ClipSequence::toQDspx() const {
+ bool ClipSequence::moveToAnotherClipSequence(Clip *item, ClipSequence *sequence) {
+ Q_D(ClipSequence);
+ return d->pModel->strategy->moveToAnotherSequenceContainer(handle(), item->handle(), sequence->handle());
+ }
+
+ std::vector ClipSequence::toOpenDspx() const {
Q_D(const ClipSequence);
- QList ret;
+ std::vector ret;
ret.reserve(d->pointContainer.size());
for (const auto &[_, item] : d->pointContainer.m_items) {
- ret.append(item->toQDspx());
+ ret.push_back(item->toOpenDspx());
}
return ret;
}
- void ClipSequence::fromQDspx(const QList &clips) {
+ void ClipSequence::fromOpenDspx(const std::vector &clips) {
while (size()) {
removeItem(firstItem());
}
for (const auto &clip : clips) {
Clip *item = nullptr;
switch (clip->type) {
- case QDspx::Clip::Audio:
+ case opendspx::Clip::Type::Audio:
item = model()->createAudioClip();
break;
- case QDspx::Clip::Singing:
+ case opendspx::Clip::Type::Singing:
item = model()->createSingingClip();
break;
default:
Q_UNREACHABLE();
}
- item->fromQDspx(clip);
+ item->fromOpenDspx(clip);
insertItem(item);
}
}
@@ -125,6 +184,14 @@ namespace dspx {
Q_D(ClipSequence);
d->handleTakeFromSequenceContainer(takenEntity, entity);
}
+ void ClipSequence::handleMoveFromAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) {
+ Q_D(ClipSequence);
+ d->handleMoveFromAnotherSequenceContainer(entity, otherSequenceContainerEntity);
+ }
+ void ClipSequence::handleMoveToAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) {
+ Q_D(ClipSequence);
+ d->handleMoveToAnotherSequenceContainer(entity, otherSequenceContainerEntity);
+ }
}
diff --git a/src/libs/application/dspxmodel/src/ClipSequence.h b/src/libs/application/dspxmodel/src/ClipSequence.h
index 26ae777c..3df51ae0 100644
--- a/src/libs/application/dspxmodel/src/ClipSequence.h
+++ b/src/libs/application/dspxmodel/src/ClipSequence.h
@@ -6,9 +6,9 @@
#include
#include
-namespace QDspx {
+namespace opendspx {
struct Clip;
- using ClipRef = QSharedPointer;
+ using ClipRef = std::shared_ptr;
}
namespace dspx {
@@ -41,9 +41,10 @@ namespace dspx {
Q_INVOKABLE bool insertItem(Clip *item);
Q_INVOKABLE bool removeItem(Clip *item);
+ Q_INVOKABLE bool moveToAnotherClipSequence(Clip *item, ClipSequence *sequence);
- QList toQDspx() const;
- void fromQDspx(const QList &clips);
+ std::vector toOpenDspx() const;
+ void fromOpenDspx(const std::vector &clips);
Track *track() const;
@@ -52,10 +53,10 @@ namespace dspx {
}
Q_SIGNALS:
- void itemAboutToInsert(Clip *item);
- void itemInserted(Clip *item);
- void itemAboutToRemove(Clip *item);
- void itemRemoved(Clip *item);
+ void itemAboutToInsert(Clip *item, ClipSequence *clipSequenceFromWhichMoved = nullptr);
+ void itemInserted(Clip *item, ClipSequence *clipSequenceFromWhichMoved = nullptr);
+ void itemAboutToRemove(Clip *item, ClipSequence *clipSequenceToWhichMoved = nullptr);
+ void itemRemoved(Clip *item, ClipSequence *clipSequenceToWhichMoved = nullptr);
void sizeChanged(int size);
void firstItemChanged(Clip *item);
void lastItemChanged(Clip *item);
@@ -63,6 +64,8 @@ namespace dspx {
protected:
void handleInsertIntoSequenceContainer(Handle entity) override;
void handleTakeFromSequenceContainer(Handle takenEntity, Handle entity) override;
+ void handleMoveFromAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) override;
+ void handleMoveToAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) override;
private:
friend class ModelPrivate;
diff --git a/src/libs/application/dspxmodel/src/ClipSequence_p.h b/src/libs/application/dspxmodel/src/ClipSequence_p.h
index b6c27acb..78f7d8cd 100644
--- a/src/libs/application/dspxmodel/src/ClipSequence_p.h
+++ b/src/libs/application/dspxmodel/src/ClipSequence_p.h
@@ -8,10 +8,13 @@
namespace dspx {
- class ClipSequencePrivate : public RangeSequenceData {
+ class ClipSequencePrivate : public RangeSequenceData {
Q_DECLARE_PUBLIC(ClipSequence)
public:
Track *track{};
+
+ void handleMoveFromAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity);
+ void handleMoveToAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity);
};
}
diff --git a/src/libs/application/dspxmodel/src/ClipTime.cpp b/src/libs/application/dspxmodel/src/ClipTime.cpp
index 6e80b886..0a786bbb 100644
--- a/src/libs/application/dspxmodel/src/ClipTime.cpp
+++ b/src/libs/application/dspxmodel/src/ClipTime.cpp
@@ -1,6 +1,4 @@
#include "ClipTime.h"
-
-#include
#include
#include
@@ -21,56 +19,9 @@ namespace dspx {
int length;
int clipStart;
int clipLen;
-
- void setLengthUnchecked(int length_);
- void setLength(int length_);
- void setClipStartUnchecked(int clipStart_);
- void setClipStart(int clipStart_);
- void setClipLenUnchecked(int clipLen_);
- void setClipLen(int clipLen_);
};
- void ClipTimePrivate::setLengthUnchecked(int length_) {
- Q_Q(ClipTime);
- pModel->strategy->setEntityProperty(handle, ModelStrategy::P_Length, length_);
- }
-
- void ClipTimePrivate::setLength(int length_) {
- Q_Q(ClipTime);
- if (auto engine = qjsEngine(q); engine && length_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Length must be greater than or equal to 0"));
- return;
- }
- setLengthUnchecked(length_);
- }
-
- void ClipTimePrivate::setClipStartUnchecked(int clipStart_) {
- Q_Q(ClipTime);
- pModel->strategy->setEntityProperty(handle, ModelStrategy::P_ClipStart, clipStart_);
- }
- void ClipTimePrivate::setClipStart(int clipStart_) {
- Q_Q(ClipTime);
- if (auto engine = qjsEngine(q); engine && clipStart_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("ClipStart must be greater than or equal to 0"));
- return;
- }
- setClipStartUnchecked(clipStart_);
- }
-
- void ClipTimePrivate::setClipLenUnchecked(int clipLen_) {
- Q_Q(ClipTime);
- pModel->strategy->setEntityProperty(handle, ModelStrategy::P_ClipLength, clipLen_);
- }
-
- void ClipTimePrivate::setClipLen(int clipLen_) {
- Q_Q(ClipTime);
- if (auto engine = qjsEngine(q); engine && clipLen_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("ClipLen must be greater than or equal to 0"));
- return;
- }
- setClipLenUnchecked(clipLen_);
- }
ClipTime::ClipTime(Handle handle, Model *model) : QObject(model), d_ptr(new ClipTimePrivate) {
Q_D(ClipTime);
@@ -103,7 +54,7 @@ namespace dspx {
void ClipTime::setLength(int length) {
Q_D(ClipTime);
Q_ASSERT(length >= 0);
- d->setLengthUnchecked(length);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_Length, length);
}
int ClipTime::clipStart() const {
@@ -114,7 +65,7 @@ namespace dspx {
void ClipTime::setClipStart(int clipStart) {
Q_D(ClipTime);
Q_ASSERT(clipStart >= 0);
- d->setClipStartUnchecked(clipStart);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_ClipStart, clipStart);
}
int ClipTime::clipLen() const {
@@ -125,20 +76,20 @@ namespace dspx {
void ClipTime::setClipLen(int clipLen) {
Q_D(ClipTime);
Q_ASSERT(clipLen >= 0);
- d->setClipLenUnchecked(clipLen);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_ClipLength, clipLen);
}
- QDspx::ClipTime ClipTime::toQDspx() const {
+ opendspx::ClipTime ClipTime::toOpenDspx() const {
return {
- .start = start(),
+ .pos = start() + clipStart(),
.length = length(),
.clipStart = clipStart(),
.clipLen = clipLen()
};
}
- void ClipTime::fromQDspx(const QDspx::ClipTime &clipTime) {
- setStart(clipTime.start);
+ void ClipTime::fromOpenDspx(const opendspx::ClipTime &clipTime) {
+ setStart(clipTime.pos - clipTime.clipStart);
setLength(clipTime.length);
setClipStart(clipTime.clipStart);
setClipLen(clipTime.clipLen);
diff --git a/src/libs/application/dspxmodel/src/ClipTime.h b/src/libs/application/dspxmodel/src/ClipTime.h
index a4621347..12e0dcf5 100644
--- a/src/libs/application/dspxmodel/src/ClipTime.h
+++ b/src/libs/application/dspxmodel/src/ClipTime.h
@@ -7,7 +7,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct ClipTime;
}
@@ -18,15 +18,15 @@ namespace dspx {
class ClipTimePrivate;
- class ClipTime : public QObject {
+ class DSPX_MODEL_EXPORT ClipTime : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(ClipTime)
Q_PROPERTY(int start READ start WRITE setStart NOTIFY startChanged)
- Q_PRIVATE_PROPERTY(d_func(), int length MEMBER length WRITE setLength NOTIFY lengthChanged)
- Q_PRIVATE_PROPERTY(d_func(), int clipStart MEMBER clipStart WRITE setClipStart NOTIFY clipStartChanged)
- Q_PRIVATE_PROPERTY(d_func(), int clipLen MEMBER clipLen WRITE setClipLen NOTIFY clipLenChanged)
+ Q_PROPERTY(int length READ length WRITE setLength NOTIFY lengthChanged)
+ Q_PROPERTY(int clipStart READ clipStart WRITE setClipStart NOTIFY clipStartChanged)
+ Q_PROPERTY(int clipLen READ clipLen WRITE setClipLen NOTIFY clipLenChanged)
public:
~ClipTime() override;
@@ -43,8 +43,8 @@ namespace dspx {
int clipLen() const;
void setClipLen(int clipLen);
- QDspx::ClipTime toQDspx() const;
- void fromQDspx(const QDspx::ClipTime &clipTime);
+ opendspx::ClipTime toOpenDspx() const;
+ void fromOpenDspx(const opendspx::ClipTime &clipTime);
Q_SIGNALS:
void startChanged(int start);
diff --git a/src/libs/application/dspxmodel/src/Clip_p.h b/src/libs/application/dspxmodel/src/Clip_p.h
index e3a3c02c..a2e8cba5 100644
--- a/src/libs/application/dspxmodel/src/Clip_p.h
+++ b/src/libs/application/dspxmodel/src/Clip_p.h
@@ -15,11 +15,15 @@ namespace dspx {
ClipTime *time;
Clip::ClipType type;
ClipSequence *clipSequence{};
+ Clip *previousItem{};
+ Clip *nextItem{};
Workspace *workspace;
bool overlapped{};
static void setOverlapped(Clip *item, bool overlapped);
static void setClipSequence(Clip *item, ClipSequence *clipSequence);
+ static void setPreviousItem(Clip *item, Clip *previousItem);
+ static void setNextItem(Clip *item, Clip *nextItem);
};
}
diff --git a/src/libs/application/dspxmodel/src/Control.cpp b/src/libs/application/dspxmodel/src/Control.cpp
index d0c823ca..4d8beb45 100644
--- a/src/libs/application/dspxmodel/src/Control.cpp
+++ b/src/libs/application/dspxmodel/src/Control.cpp
@@ -1,6 +1,4 @@
#include "Control.h"
-
-#include
#include
#include
@@ -19,40 +17,10 @@ namespace dspx {
double pan;
bool mute;
- void setGainUnchecked(double gain_);
- void setGain(double gain_);
- void setPanUnchecked(double pan_);
- void setPan(double pan_);
};
- void ControlPrivate::setGainUnchecked(double gain_) {
- Q_Q(Control);
- pModel->strategy->setEntityProperty(handle, ModelStrategy::P_ControlGain, gain_);
- }
-
- void ControlPrivate::setGain(double gain_) {
- Q_Q(Control);
- if (auto engine = qjsEngine(q); engine && (gain_ < 0)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Gain must be greater or equal to 0"));
- return;
- }
- setGainUnchecked(gain_);
- }
- void ControlPrivate::setPanUnchecked(double pan_) {
- Q_Q(Control);
- pModel->strategy->setEntityProperty(handle, ModelStrategy::P_ControlPan, pan_);
- }
-
- void ControlPrivate::setPan(double pan_) {
- Q_Q(Control);
- if (auto engine = qjsEngine(q); engine && (pan_ < -1 || pan_ > 1)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Pan must be in range [-1.0, 1.0]"));
- return;
- }
- setPanUnchecked(pan_);
- }
Control::Control(Handle handle, Model *model) : QObject(model), d_ptr(new ControlPrivate) {
Q_D(Control);
@@ -74,7 +42,7 @@ namespace dspx {
void Control::setGain(double gain) {
Q_D(Control);
Q_ASSERT(gain >= 0.0);
- d->setGainUnchecked(gain);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_ControlGain, gain);
}
double Control::pan() const {
@@ -85,7 +53,7 @@ namespace dspx {
void Control::setPan(double pan) {
Q_D(Control);
Q_ASSERT(pan >= -1.0 && pan <= 1.0);
- d->setPanUnchecked(pan);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_ControlPan, pan);
}
bool Control::mute() const {
diff --git a/src/libs/application/dspxmodel/src/Control.h b/src/libs/application/dspxmodel/src/Control.h
index 20135658..d0330ec7 100644
--- a/src/libs/application/dspxmodel/src/Control.h
+++ b/src/libs/application/dspxmodel/src/Control.h
@@ -14,13 +14,13 @@ namespace dspx {
class ControlPrivate;
- class Control : public QObject {
+ class DSPX_MODEL_EXPORT Control : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(Control)
- Q_PRIVATE_PROPERTY(d_func(), double gain MEMBER gain WRITE setGain NOTIFY gainChanged)
- Q_PRIVATE_PROPERTY(d_func(), double pan MEMBER pan WRITE setPan NOTIFY panChanged)
+ Q_PROPERTY(double gain READ gain WRITE setGain NOTIFY gainChanged)
+ Q_PROPERTY(double pan READ pan WRITE setPan NOTIFY panChanged)
Q_PROPERTY(bool mute READ mute WRITE setMute NOTIFY muteChanged)
public:
diff --git a/src/libs/application/dspxmodel/src/EntityObject.cpp b/src/libs/application/dspxmodel/src/EntityObject.cpp
index a42f104a..75019821 100644
--- a/src/libs/application/dspxmodel/src/EntityObject.cpp
+++ b/src/libs/application/dspxmodel/src/EntityObject.cpp
@@ -22,7 +22,7 @@ namespace dspx {
EntityObject::~EntityObject() {
Q_D(EntityObject);
if (d->model && d->handle) {
-
+ Q_ASSERT(false && "EntityObject::~EntityObject: handle is not null. You should call Model::destroyItem() to delete EntityObject.");
}
}
@@ -45,6 +45,12 @@ namespace dspx {
void EntityObject::handleInsertIntoMapContainer(Handle entity, const QString &key) {
Q_UNREACHABLE();
}
+ void EntityObject::handleMoveToAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) {
+ Q_UNREACHABLE();
+ }
+ void EntityObject::handleMoveFromAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity) {
+ Q_UNREACHABLE();
+ }
void EntityObject::handleTakeFromSequenceContainer(Handle takenEntity, Handle entity) {
Q_UNREACHABLE();
}
diff --git a/src/libs/application/dspxmodel/src/EntityObject.h b/src/libs/application/dspxmodel/src/EntityObject.h
index 1d9e89c4..c4cb85a8 100644
--- a/src/libs/application/dspxmodel/src/EntityObject.h
+++ b/src/libs/application/dspxmodel/src/EntityObject.h
@@ -29,6 +29,9 @@ namespace dspx {
virtual void handleInsertIntoListContainer(Handle entities, int index);
virtual void handleInsertIntoMapContainer(Handle entity, const QString &key);
+ virtual void handleMoveToAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity);
+ virtual void handleMoveFromAnotherSequenceContainer(Handle entity, Handle otherSequenceContainerEntity);
+
virtual void handleTakeFromSequenceContainer(Handle takenEntity, Handle entity);
virtual void handleTakeFromListContainer(Handle takenEntities, int index);
virtual void handleTakeFromMapContainer(Handle takenEntity, const QString &key);
diff --git a/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp b/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp
index 6f085afa..26cc8353 100644
--- a/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp
+++ b/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp
@@ -49,13 +49,13 @@ namespace dspx {
return d->pModel->strategy->rotateDataArray(handle(), leftIndex, middleIndex, rightIndex);
}
- QList FreeValueDataArray::toQDspx() const {
+ std::vector FreeValueDataArray::toOpenDspx() const {
Q_D(const FreeValueDataArray);
- return d->data;
+ return std::vector(d->data.cbegin(), d->data.cend());
}
- void FreeValueDataArray::fromQDspx(const QList &values) {
- splice(0, size(), values);
+ void FreeValueDataArray::fromOpenDspx(const std::vector &values) {
+ splice(0, size(), QList(values.begin(), values.end()));
}
void FreeValueDataArray::handleSpliceDataArray(int index, int length, const QVariantList &values) {
diff --git a/src/libs/application/dspxmodel/src/FreeValueDataArray.h b/src/libs/application/dspxmodel/src/FreeValueDataArray.h
index 2c9a263a..c3c5c819 100644
--- a/src/libs/application/dspxmodel/src/FreeValueDataArray.h
+++ b/src/libs/application/dspxmodel/src/FreeValueDataArray.h
@@ -28,8 +28,8 @@ namespace dspx {
Q_INVOKABLE QList slice(int index, int length) const;
Q_INVOKABLE bool rotate(int leftIndex, int middleIndex, int rightIndex);
- QList toQDspx() const;
- void fromQDspx(const QList &values);
+ std::vector toOpenDspx() const;
+ void fromOpenDspx(const std::vector &values);
ParamCurveFree *paramCurveFree() const;
diff --git a/src/libs/application/dspxmodel/src/Global.cpp b/src/libs/application/dspxmodel/src/Global.cpp
index e687463f..463526d1 100644
--- a/src/libs/application/dspxmodel/src/Global.cpp
+++ b/src/libs/application/dspxmodel/src/Global.cpp
@@ -1,6 +1,4 @@
#include "Global.h"
-
-#include
#include
#include
@@ -17,30 +15,8 @@ namespace dspx {
Global *q_ptr;
ModelPrivate *pModel;
Handle handle;
-
- int centShift() const;
- void setCentShiftUnchecked(int centShift);
- void setCentShift(int centShift);
};
- int GlobalPrivate::centShift() const {
- return pModel->centShift;
- }
-
- void GlobalPrivate::setCentShiftUnchecked(int centShift) {
- Q_Q(Global);
- pModel->strategy->setEntityProperty(handle, ModelStrategy::P_CentShift, centShift);
- }
-
- void GlobalPrivate::setCentShift(int centShift) {
- Q_Q(Global);
- if (auto engine = qjsEngine(q); engine && (centShift < -50 || centShift > 50)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Cent shift must be in range [-50, 50]"));
- return;
- }
- setCentShiftUnchecked(centShift);
- }
-
Global::Global(Model *model) : QObject(model), d_ptr(new GlobalPrivate) {
Q_D(Global);
d->q_ptr = this;
@@ -67,12 +43,12 @@ namespace dspx {
}
int Global::centShift() const {
Q_D(const Global);
- return d->centShift();
+ return d->pModel->centShift;
}
void Global::setCentShift(int centShift) {
Q_D(Global);
Q_ASSERT(centShift >= -50 && centShift <= 50);
- d->setCentShiftUnchecked(centShift);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_CentShift, centShift);
}
QString Global::editorId() const {
Q_D(const Global);
@@ -91,22 +67,22 @@ namespace dspx {
d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_EditorName, editorName);
}
- QDspx::Global Global::toQDspx() const {
+ opendspx::Global Global::toOpenDspx() const {
return {
- .author = author(),
- .name = name(),
+ .author = author().toStdString(),
+ .name = name().toStdString(),
.centShift = centShift(),
- .editorId = editorId(),
- .editorName = editorName()
+ .editorId = editorId().toStdString(),
+ .editorName = editorName().toStdString()
};
}
- void Global::fromQDspx(const QDspx::Global &global) {
- setAuthor(global.author);
- setName(global.name);
+ void Global::fromOpenDspx(const opendspx::Global &global) {
+ setAuthor(QString::fromStdString(global.author));
+ setName(QString::fromStdString(global.name));
setCentShift(global.centShift);
- setEditorId(global.editorId);
- setEditorName(global.editorName);
+ setEditorId(QString::fromStdString(global.editorId));
+ setEditorName(QString::fromStdString(global.editorName));
}
}
diff --git a/src/libs/application/dspxmodel/src/Global.h b/src/libs/application/dspxmodel/src/Global.h
index 651f2129..6aa09687 100644
--- a/src/libs/application/dspxmodel/src/Global.h
+++ b/src/libs/application/dspxmodel/src/Global.h
@@ -5,7 +5,9 @@
#include
-namespace QDspx {
+#include
+
+namespace opendspx {
struct Global;
}
@@ -17,14 +19,14 @@ namespace dspx {
class GlobalPrivate;
- class Global : public QObject {
+ class DSPX_MODEL_EXPORT Global : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(Global)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
- Q_PRIVATE_PROPERTY(d_func(), int centShift READ centShift WRITE setCentShift NOTIFY centShiftChanged)
+ Q_PROPERTY(int centShift READ centShift WRITE setCentShift NOTIFY centShiftChanged)
Q_PROPERTY(QString editorId READ editorId WRITE setEditorId NOTIFY editorIdChanged)
Q_PROPERTY(QString editorName READ editorName WRITE setEditorName NOTIFY editorNameChanged)
@@ -46,8 +48,8 @@ namespace dspx {
QString editorName() const;
void setEditorName(const QString &editorName);
- QDspx::Global toQDspx() const;
- void fromQDspx(const QDspx::Global &global);
+ opendspx::Global toOpenDspx() const;
+ void fromOpenDspx(const opendspx::Global &global);
Q_SIGNALS:
void nameChanged(const QString &name);
diff --git a/src/libs/application/dspxmodel/src/KeySignature.cpp b/src/libs/application/dspxmodel/src/KeySignature.cpp
new file mode 100644
index 00000000..1ff268cf
--- /dev/null
+++ b/src/libs/application/dspxmodel/src/KeySignature.cpp
@@ -0,0 +1,174 @@
+#include "KeySignature.h"
+#include "KeySignature_p.h"
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+namespace dspx {
+
+ void KeySignaturePrivate::setKeySignatureSequence(KeySignature *item, KeySignatureSequence *keySignatureSequence) {
+ auto d = item->d_func();
+ if (d->keySignatureSequence != keySignatureSequence) {
+ d->keySignatureSequence = keySignatureSequence;
+ Q_EMIT item->keySignatureSequenceChanged();
+ }
+ }
+
+ void KeySignaturePrivate::setPreviousItem(KeySignature *item, KeySignature *previousItem) {
+ auto d = item->d_func();
+ if (d->previousItem != previousItem) {
+ d->previousItem = previousItem;
+ Q_EMIT item->previousItemChanged();
+ }
+ }
+
+ void KeySignaturePrivate::setNextItem(KeySignature *item, KeySignature *nextItem) {
+ auto d = item->d_func();
+ if (d->nextItem != nextItem) {
+ d->nextItem = nextItem;
+ Q_EMIT item->nextItemChanged();
+ }
+ }
+
+ KeySignature::KeySignature(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new KeySignaturePrivate) {
+ Q_D(KeySignature);
+ Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_KeySignature);
+ d->q_ptr = this;
+ d->pos = model->strategy()->getEntityProperty(handle, ModelStrategy::P_Position).toInt();
+ d->mode = model->strategy()->getEntityProperty(handle, ModelStrategy::P_Mode).toInt();
+ d->tonality = model->strategy()->getEntityProperty(handle, ModelStrategy::P_Tonality).toInt();
+ d->accidentalType = static_cast(model->strategy()->getEntityProperty(handle, ModelStrategy::P_AccidentalType).toInt());
+ }
+
+ KeySignature::~KeySignature() = default;
+
+ int KeySignature::pos() const {
+ Q_D(const KeySignature);
+ return d->pos;
+ }
+
+ void KeySignature::setPos(int pos) {
+ Q_D(KeySignature);
+ Q_ASSERT(pos >= 0);
+ model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Position, pos);
+ }
+
+ int KeySignature::mode() const {
+ Q_D(const KeySignature);
+ return d->mode;
+ }
+
+ void KeySignature::setMode(int mode) {
+ Q_D(KeySignature);
+ Q_ASSERT(mode >= 0 && mode <= 4095);
+ model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Mode, mode);
+ }
+
+ int KeySignature::tonality() const {
+ Q_D(const KeySignature);
+ return d->tonality;
+ }
+
+ void KeySignature::setTonality(int tonality) {
+ Q_D(KeySignature);
+ Q_ASSERT(tonality >= 0 && tonality <= 11);
+ model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Tonality, tonality);
+ }
+
+ KeySignature::AccidentalType KeySignature::accidentalType() const {
+ Q_D(const KeySignature);
+ return d->accidentalType;
+ }
+
+ void KeySignature::setAccidentalType(AccidentalType accidentalType) {
+ Q_D(KeySignature);
+ Q_ASSERT(accidentalType == Flat || accidentalType == Sharp);
+ model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_AccidentalType, static_cast(accidentalType));
+ }
+
+ KeySignatureSequence *KeySignature::keySignatureSequence() const {
+ Q_D(const KeySignature);
+ return d->keySignatureSequence;
+ }
+
+ KeySignature *KeySignature::previousItem() const {
+ Q_D(const KeySignature);
+ return d->previousItem;
+ }
+
+ KeySignature *KeySignature::nextItem() const {
+ Q_D(const KeySignature);
+ return d->nextItem;
+ }
+
+ nlohmann::json KeySignature::toOpenDspx() const {
+ return nlohmann::json::object({
+ {"pos", pos()},
+ {"mode", mode()},
+ {"tonality", tonality()},
+ {"accidentalType", accidentalType()}
+ });
+ }
+
+ void KeySignature::fromOpenDspx(const nlohmann::json &keySignature) {
+ try {
+ auto pos = keySignature.at("pos").get();
+ pos = qMax(0, pos);
+ setPos(pos);
+ auto mode = keySignature.at("mode").get();
+ if (mode < 0 || mode > 4095) {
+ mode = 0;
+ }
+ setMode(mode);
+ auto tonality = keySignature.at("tonality").get();
+ if (tonality < 0 || tonality > 11) {
+ tonality = 0;
+ }
+ setTonality(tonality);
+ auto accidentalType = keySignature.at("accidentalType").get();
+ if (accidentalType != Flat && accidentalType != Sharp) {
+ accidentalType = Flat;
+ }
+ setAccidentalType(static_cast(accidentalType));
+ } catch (const nlohmann::json::exception &) {
+ // ignore
+ }
+ }
+
+ void KeySignature::handleSetEntityProperty(int property, const QVariant &value) {
+ Q_D(KeySignature);
+ switch (property) {
+ case ModelStrategy::P_Position: {
+ d->pos = value.toInt();
+ Q_EMIT posChanged(d->pos);
+ break;
+ }
+ case ModelStrategy::P_Mode: {
+ d->mode = value.toInt();
+ Q_EMIT modeChanged(d->mode);
+ break;
+ }
+ case ModelStrategy::P_Tonality: {
+ d->tonality = value.toInt();
+ Q_EMIT tonalityChanged(d->tonality);
+ break;
+ }
+ case ModelStrategy::P_AccidentalType: {
+ d->accidentalType = static_cast(value.toInt());
+ Q_EMIT accidentalTypeChanged(d->accidentalType);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+}
+
+#include "moc_KeySignature.cpp"
diff --git a/src/libs/application/dspxmodel/src/KeySignature.h b/src/libs/application/dspxmodel/src/KeySignature.h
new file mode 100644
index 00000000..ca297db1
--- /dev/null
+++ b/src/libs/application/dspxmodel/src/KeySignature.h
@@ -0,0 +1,73 @@
+#ifndef DIFFSCOPE_DSPX_MODEL_KEYSIGNATURE_H
+#define DIFFSCOPE_DSPX_MODEL_KEYSIGNATURE_H
+
+#include
+
+#include
+
+#include
+
+namespace dspx {
+
+ class KeySignatureSequence;
+ class KeySignaturePrivate;
+
+ class DSPX_MODEL_EXPORT KeySignature : public EntityObject {
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+ Q_DECLARE_PRIVATE(KeySignature);
+ Q_PROPERTY(int pos READ pos WRITE setPos NOTIFY posChanged)
+ Q_PROPERTY(int mode READ mode WRITE setMode NOTIFY modeChanged)
+ Q_PROPERTY(int tonality READ tonality WRITE setTonality NOTIFY tonalityChanged)
+ Q_PROPERTY(AccidentalType accidentalType READ accidentalType WRITE setAccidentalType NOTIFY accidentalTypeChanged)
+ public:
+ enum AccidentalType {
+ Flat = 0,
+ Sharp = 1
+ };
+ Q_ENUM(AccidentalType)
+
+ ~KeySignature() override;
+
+ int pos() const;
+ void setPos(int pos);
+
+ int mode() const;
+ void setMode(int mode);
+
+ int tonality() const;
+ void setTonality(int tonality);
+
+ AccidentalType accidentalType() const;
+ void setAccidentalType(AccidentalType accidentalType);
+
+ KeySignatureSequence *keySignatureSequence() const;
+
+ KeySignature *previousItem() const;
+ KeySignature *nextItem() const;
+
+ nlohmann::json toOpenDspx() const;
+ void fromOpenDspx(const nlohmann::json &keySignature);
+
+ Q_SIGNALS:
+ void posChanged(int pos);
+ void modeChanged(int mode);
+ void tonalityChanged(int tonality);
+ void accidentalTypeChanged(AccidentalType accidentalType);
+ void keySignatureSequenceChanged();
+ void previousItemChanged();
+ void nextItemChanged();
+
+ protected:
+ void handleSetEntityProperty(int property, const QVariant &value) override;
+
+ private:
+ friend class ModelPrivate;
+ explicit KeySignature(Handle handle, Model *model);
+ QScopedPointer d_ptr;
+ };
+
+}
+
+#endif //DIFFSCOPE_DSPX_MODEL_KEYSIGNATURE_H
diff --git a/src/libs/application/dspxmodel/src/KeySignatureSequence.cpp b/src/libs/application/dspxmodel/src/KeySignatureSequence.cpp
new file mode 100644
index 00000000..41797737
--- /dev/null
+++ b/src/libs/application/dspxmodel/src/KeySignatureSequence.cpp
@@ -0,0 +1,117 @@
+#include "KeySignatureSequence.h"
+#include "KeySignatureSequence_p.h"
+
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace dspx {
+
+ KeySignatureSequence::KeySignatureSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new KeySignatureSequencePrivate) {
+ Q_D(KeySignatureSequence);
+ Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_KeySignatures);
+ d->q_ptr = this;
+ d->pModel = ModelPrivate::get(model);
+
+ d->init(model->strategy()->getEntitiesFromSequenceContainer(handle));
+ }
+
+ KeySignatureSequence::~KeySignatureSequence() = default;
+
+ int KeySignatureSequence::size() const {
+ Q_D(const KeySignatureSequence);
+ return d->container.size();
+ }
+
+ KeySignature *KeySignatureSequence::firstItem() const {
+ Q_D(const KeySignatureSequence);
+ return d->firstItem;
+ }
+
+ KeySignature *KeySignatureSequence::lastItem() const {
+ Q_D(const KeySignatureSequence);
+ return d->lastItem;
+ }
+
+ KeySignature *KeySignatureSequence::previousItem(KeySignature *item) const {
+ Q_D(const KeySignatureSequence);
+ return d->container.previousItem(item);
+ }
+
+ KeySignature *KeySignatureSequence::nextItem(KeySignature *item) const {
+ Q_D(const KeySignatureSequence);
+ return d->container.nextItem(item);
+ }
+
+ QList KeySignatureSequence::slice(int position, int length) const {
+ Q_D(const KeySignatureSequence);
+ return d->container.slice(position, length);
+ }
+
+ KeySignature *KeySignatureSequence::itemAt(int position) const {
+ Q_D(const KeySignatureSequence);
+ auto it = d->container.m_items.upper_bound(position);
+ if (it != d->container.m_items.begin()) {
+ --it;
+ return it->second;
+ }
+ return nullptr;
+ }
+
+ bool KeySignatureSequence::contains(KeySignature *item) const {
+ Q_D(const KeySignatureSequence);
+ return d->container.contains(item);
+ }
+
+ bool KeySignatureSequence::insertItem(KeySignature *item) {
+ Q_D(KeySignatureSequence);
+ return d->pModel->strategy->insertIntoSequenceContainer(handle(), item->handle());
+ }
+
+ bool KeySignatureSequence::removeItem(KeySignature *item) {
+ Q_D(KeySignatureSequence);
+ return d->pModel->strategy->takeFromSequenceContainer(handle(), item->handle());
+ }
+
+ nlohmann::json KeySignatureSequence::toOpenDspx() const {
+ Q_D(const KeySignatureSequence);
+ nlohmann::json ret = nlohmann::json::array();
+ for (const auto &[_, item] : d->container.m_items) {
+ ret.push_back(item->toOpenDspx());
+ }
+ return ret;
+ }
+
+ void KeySignatureSequence::fromOpenDspx(const nlohmann::json &keySignatures) {
+ while (size()) {
+ removeItem(firstItem());
+ }
+ if (!keySignatures.is_array())
+ return;
+ for (const auto &value : keySignatures) {
+ auto item = model()->createKeySignature();
+ item->fromOpenDspx(value);
+ insertItem(item);
+ }
+ }
+
+ void KeySignatureSequence::handleInsertIntoSequenceContainer(Handle entity) {
+ Q_D(KeySignatureSequence);
+ d->handleInsertIntoSequenceContainer(entity);
+ }
+
+ void KeySignatureSequence::handleTakeFromSequenceContainer(Handle takenEntity, Handle entity) {
+ Q_D(KeySignatureSequence);
+ d->handleTakeFromSequenceContainer(takenEntity, entity);
+ }
+
+}
+
+#include "moc_KeySignatureSequence.cpp"
diff --git a/src/libs/application/dspxmodel/src/KeySignatureSequence.h b/src/libs/application/dspxmodel/src/KeySignatureSequence.h
new file mode 100644
index 00000000..219092bd
--- /dev/null
+++ b/src/libs/application/dspxmodel/src/KeySignatureSequence.h
@@ -0,0 +1,69 @@
+#ifndef DIFFSCOPE_DSPX_MODEL_KEYSIGNATURESEQUENCE_H
+#define DIFFSCOPE_DSPX_MODEL_KEYSIGNATURESEQUENCE_H
+
+#include
+
+#include
+
+#include
+#include
+
+namespace dspx {
+
+ class KeySignature;
+
+ class KeySignatureSequencePrivate;
+
+ class DSPX_MODEL_EXPORT KeySignatureSequence : public EntityObject {
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+ Q_DECLARE_PRIVATE(KeySignatureSequence)
+ Q_PROPERTY(int size READ size NOTIFY sizeChanged)
+ Q_PROPERTY(KeySignature *firstItem READ firstItem NOTIFY firstItemChanged)
+ Q_PROPERTY(KeySignature *lastItem READ lastItem NOTIFY lastItemChanged)
+ Q_PRIVATE_PROPERTY(d_func(), QJSValue iterable READ iterable CONSTANT)
+ public:
+ ~KeySignatureSequence() override;
+
+ int size() const;
+ KeySignature *firstItem() const;
+ KeySignature *lastItem() const;
+ Q_INVOKABLE KeySignature *previousItem(KeySignature *item) const;
+ Q_INVOKABLE KeySignature *nextItem(KeySignature *item) const;
+ Q_INVOKABLE QList slice(int position, int length) const;
+ Q_INVOKABLE KeySignature *itemAt(int position) const;
+ Q_INVOKABLE bool contains(KeySignature *item) const;
+
+ Q_INVOKABLE bool insertItem(KeySignature *item);
+ Q_INVOKABLE bool removeItem(KeySignature *item);
+
+ nlohmann::json toOpenDspx() const;
+ void fromOpenDspx(const nlohmann::json &keySignatures);
+
+ auto asRange() const {
+ return impl::SequenceRange(this);
+ }
+
+ Q_SIGNALS:
+ void itemAboutToInsert(KeySignature *item);
+ void itemInserted(KeySignature *item);
+ void itemAboutToRemove(KeySignature *item);
+ void itemRemoved(KeySignature *item);
+ void sizeChanged(int size);
+ void firstItemChanged(KeySignature *item);
+ void lastItemChanged(KeySignature *item);
+
+ protected:
+ void handleInsertIntoSequenceContainer(Handle entity) override;
+ void handleTakeFromSequenceContainer(Handle takenEntity, Handle entity) override;
+
+ private:
+ friend class ModelPrivate;
+ explicit KeySignatureSequence(Handle handle, Model *model);
+ QScopedPointer d_ptr;
+ };
+
+}
+
+#endif //DIFFSCOPE_DSPX_MODEL_KEYSIGNATURESEQUENCE_H
diff --git a/src/libs/application/dspxmodel/src/KeySignatureSequence_p.h b/src/libs/application/dspxmodel/src/KeySignatureSequence_p.h
new file mode 100644
index 00000000..7c7e6cb7
--- /dev/null
+++ b/src/libs/application/dspxmodel/src/KeySignatureSequence_p.h
@@ -0,0 +1,17 @@
+#ifndef DIFFSCOPE_DSPX_MODEL_KEYSIGNATURESEQUENCE_P_H
+#define DIFFSCOPE_DSPX_MODEL_KEYSIGNATURESEQUENCE_P_H
+
+#include
+
+#include
+#include
+
+namespace dspx {
+
+ class KeySignatureSequencePrivate : public PointSequenceData {
+ Q_DECLARE_PUBLIC(KeySignatureSequence)
+ };
+
+}
+
+#endif //DIFFSCOPE_DSPX_MODEL_KEYSIGNATURESEQUENCE_P_H
diff --git a/src/libs/application/dspxmodel/src/KeySignature_p.h b/src/libs/application/dspxmodel/src/KeySignature_p.h
new file mode 100644
index 00000000..d7627875
--- /dev/null
+++ b/src/libs/application/dspxmodel/src/KeySignature_p.h
@@ -0,0 +1,27 @@
+#ifndef DIFFSCOPE_DSPX_MODEL_KEYSIGNATURE_P_H
+#define DIFFSCOPE_DSPX_MODEL_KEYSIGNATURE_P_H
+
+#include
+
+namespace dspx {
+
+ class KeySignaturePrivate {
+ Q_DECLARE_PUBLIC(KeySignature)
+ public:
+ KeySignature *q_ptr;
+ int pos;
+ int mode;
+ int tonality;
+ KeySignature::AccidentalType accidentalType;
+ KeySignatureSequence *keySignatureSequence{};
+ KeySignature *previousItem{};
+ KeySignature *nextItem{};
+
+ static void setKeySignatureSequence(KeySignature *item, KeySignatureSequence *keySignatureSequence);
+ static void setPreviousItem(KeySignature *item, KeySignature *previousItem);
+ static void setNextItem(KeySignature *item, KeySignature *nextItem);
+ };
+
+}
+
+#endif //DIFFSCOPE_DSPX_MODEL_KEYSIGNATURE_P_H
diff --git a/src/libs/application/dspxmodel/src/Label.cpp b/src/libs/application/dspxmodel/src/Label.cpp
index 7fdfecfe..127ad1ec 100644
--- a/src/libs/application/dspxmodel/src/Label.cpp
+++ b/src/libs/application/dspxmodel/src/Label.cpp
@@ -1,7 +1,5 @@
#include "Label.h"
#include "Label_p.h"
-
-#include
#include
#include
@@ -12,19 +10,7 @@
namespace dspx {
- void LabelPrivate::setPosUnchecked(int pos_) {
- Q_Q(Label);
- q->model()->strategy()->setEntityProperty(q->handle(), ModelStrategy::P_Position, pos_);
- }
- void LabelPrivate::setPos(int pos_) {
- Q_Q(Label);
- if (auto engine = qjsEngine(q); engine && pos_ < -0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater or equal to 0"));
- return;
- }
- setPosUnchecked(pos_);
- }
void LabelPrivate::setLabelSequence(Label *item, LabelSequence *labelSequence) {
auto d = item->d_func();
@@ -34,6 +20,22 @@ namespace dspx {
}
}
+ void LabelPrivate::setPreviousItem(Label *item, Label *previousItem) {
+ auto d = item->d_func();
+ if (d->previousItem != previousItem) {
+ d->previousItem = previousItem;
+ Q_EMIT item->previousItemChanged();
+ }
+ }
+
+ void LabelPrivate::setNextItem(Label *item, Label *nextItem) {
+ auto d = item->d_func();
+ if (d->nextItem != nextItem) {
+ d->nextItem = nextItem;
+ Q_EMIT item->nextItemChanged();
+ }
+ }
+
Label::Label(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new LabelPrivate) {
Q_D(Label);
Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_Label);
@@ -52,7 +54,7 @@ namespace dspx {
void Label::setPos(int pos) {
Q_D(Label);
Q_ASSERT(pos >= 0);
- d->setPosUnchecked(pos);
+ model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Position, pos);
}
QString Label::text() const {
@@ -70,16 +72,26 @@ namespace dspx {
return d->labelSequence;
}
- QDspx::Label Label::toQDspx() const {
+ Label *Label::previousItem() const {
+ Q_D(const Label);
+ return d->previousItem;
+ }
+
+ Label *Label::nextItem() const {
+ Q_D(const Label);
+ return d->nextItem;
+ }
+
+ opendspx::Label Label::toOpenDspx() const {
return {
.pos = pos(),
- .text = text(),
+ .text = text().toStdString(),
};
}
- void Label::fromQDspx(const QDspx::Label &label) {
+ void Label::fromOpenDspx(const opendspx::Label &label) {
setPos(label.pos);
- setText(label.text);
+ setText(QString::fromStdString(label.text));
}
void Label::handleSetEntityProperty(int property, const QVariant &value) {
diff --git a/src/libs/application/dspxmodel/src/Label.h b/src/libs/application/dspxmodel/src/Label.h
index dd21eb3f..f11e5e34 100644
--- a/src/libs/application/dspxmodel/src/Label.h
+++ b/src/libs/application/dspxmodel/src/Label.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct Label;
}
@@ -19,9 +19,11 @@ namespace dspx {
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(Label);
- Q_PRIVATE_PROPERTY(d_func(), int pos MEMBER pos WRITE setPos NOTIFY posChanged)
+ Q_PROPERTY(int pos READ pos WRITE setPos NOTIFY posChanged)
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(LabelSequence *labelSequence READ labelSequence NOTIFY labelSequenceChanged)
+ Q_PROPERTY(Label *previousItem READ previousItem NOTIFY previousItemChanged)
+ Q_PROPERTY(Label *nextItem READ nextItem NOTIFY nextItemChanged)
public:
~Label() override;
@@ -33,13 +35,18 @@ namespace dspx {
LabelSequence *labelSequence() const;
- QDspx::Label toQDspx() const;
- void fromQDspx(const QDspx::Label &label);
+ Label *previousItem() const;
+ Label *nextItem() const;
+
+ opendspx::Label toOpenDspx() const;
+ void fromOpenDspx(const opendspx::Label &label);
Q_SIGNALS:
void posChanged(int pos);
void textChanged(const QString &text);
void labelSequenceChanged();
+ void previousItemChanged();
+ void nextItemChanged();
protected:
void handleSetEntityProperty(int property, const QVariant &value) override;
diff --git a/src/libs/application/dspxmodel/src/LabelSequence.cpp b/src/libs/application/dspxmodel/src/LabelSequence.cpp
index 2eb86c2b..b7dfbe5b 100644
--- a/src/libs/application/dspxmodel/src/LabelSequence.cpp
+++ b/src/libs/application/dspxmodel/src/LabelSequence.cpp
@@ -20,13 +20,6 @@ namespace dspx {
d->pModel = ModelPrivate::get(model);
d->init(model->strategy()->getEntitiesFromSequenceContainer(handle));
-
- connect(this, &LabelSequence::itemInserted, this, [=](Label *item) {
- LabelPrivate::setLabelSequence(item, this);
- });
- connect(this, &LabelSequence::itemRemoved, this, [=](Label *item) {
- LabelPrivate::setLabelSequence(item, nullptr);
- });
}
LabelSequence::~LabelSequence() = default;
@@ -76,23 +69,23 @@ namespace dspx {
return d->pModel->strategy->takeFromSequenceContainer(handle(), item->handle());
}
- QList LabelSequence::toQDspx() const {
+ std::vector LabelSequence::toOpenDspx() const {
Q_D(const LabelSequence);
- QList ret;
+ std::vector ret;
ret.reserve(d->container.size());
for (const auto &[_, item] : d->container.m_items) {
- ret.append(item->toQDspx());
+ ret.push_back(item->toOpenDspx());
}
return ret;
}
- void LabelSequence::fromQDspx(const QList &labels) {
+ void LabelSequence::fromOpenDspx(const std::vector &labels) {
while (size()) {
removeItem(firstItem());
}
for (const auto &label : labels) {
auto item = model()->createLabel();
- item->fromQDspx(label);
+ item->fromOpenDspx(label);
insertItem(item);
}
}
diff --git a/src/libs/application/dspxmodel/src/LabelSequence.h b/src/libs/application/dspxmodel/src/LabelSequence.h
index cca09003..1c043454 100644
--- a/src/libs/application/dspxmodel/src/LabelSequence.h
+++ b/src/libs/application/dspxmodel/src/LabelSequence.h
@@ -6,7 +6,7 @@
#include
#include
-namespace QDspx {
+namespace opendspx {
struct Label;
}
@@ -39,8 +39,8 @@ namespace dspx {
Q_INVOKABLE bool insertItem(Label *item);
Q_INVOKABLE bool removeItem(Label *item);
- QList toQDspx() const;
- void fromQDspx(const QList &labels);
+ std::vector toOpenDspx() const;
+ void fromOpenDspx(const std::vector &labels);
auto asRange() const {
return impl::SequenceRange(this);
diff --git a/src/libs/application/dspxmodel/src/LabelSequence_p.h b/src/libs/application/dspxmodel/src/LabelSequence_p.h
index fe03ee4a..2bcb8c4a 100644
--- a/src/libs/application/dspxmodel/src/LabelSequence_p.h
+++ b/src/libs/application/dspxmodel/src/LabelSequence_p.h
@@ -8,7 +8,7 @@
namespace dspx {
- class LabelSequencePrivate : public PointSequenceData {
+ class LabelSequencePrivate : public PointSequenceData {
Q_DECLARE_PUBLIC(LabelSequence)
};
diff --git a/src/libs/application/dspxmodel/src/Label_p.h b/src/libs/application/dspxmodel/src/Label_p.h
index 0ef4b5b3..70e56681 100644
--- a/src/libs/application/dspxmodel/src/Label_p.h
+++ b/src/libs/application/dspxmodel/src/Label_p.h
@@ -12,11 +12,12 @@ namespace dspx {
int pos;
QString text;
LabelSequence *labelSequence{};
-
- void setPosUnchecked(int pos_);
- void setPos(int pos_);
+ Label *previousItem{};
+ Label *nextItem{};
static void setLabelSequence(Label *item, LabelSequence *labelSequence);
+ static void setPreviousItem(Label *item, Label *previousItem);
+ static void setNextItem(Label *item, Label *nextItem);
};
}
diff --git a/src/libs/application/dspxmodel/src/ListData_p.h b/src/libs/application/dspxmodel/src/ListData_p.h
index dff09987..358b707e 100644
--- a/src/libs/application/dspxmodel/src/ListData_p.h
+++ b/src/libs/application/dspxmodel/src/ListData_p.h
@@ -15,7 +15,7 @@ namespace dspx {
static QJSValue create(QObject *o);
};
- template
+ template
class ListData {
public:
ListType *q_ptr;
@@ -36,8 +36,11 @@ namespace dspx {
}
void init(const QList &handles) {
+ auto q = q_ptr;
for (auto handle : handles) {
- itemList.append(getItem(handle, true));
+ auto item = getItem(handle, true);
+ itemList.append(item);
+ setList(item, q);
}
}
@@ -45,6 +48,7 @@ namespace dspx {
auto q = q_ptr;
Q_EMIT q->itemAboutToInsert(index, item);
itemList.insert(index, item);
+ setList(item, q);
Q_EMIT q->itemInserted(index, item);
Q_EMIT q->sizeChanged(itemList.size());
Q_EMIT q->itemsChanged();
@@ -55,6 +59,7 @@ namespace dspx {
auto item = itemList.at(index);
Q_EMIT q->itemAboutToRemove(index, item);
itemList.removeAt(index);
+ setList(item, nullptr);
Q_EMIT q->itemRemoved(index, item);
Q_EMIT q->sizeChanged(itemList.size());
Q_EMIT q->itemsChanged();
diff --git a/src/libs/application/dspxmodel/src/Master.cpp b/src/libs/application/dspxmodel/src/Master.cpp
index 95dd4e05..a57f5e46 100644
--- a/src/libs/application/dspxmodel/src/Master.cpp
+++ b/src/libs/application/dspxmodel/src/Master.cpp
@@ -16,18 +16,36 @@ namespace dspx {
public:
Master *q_ptr;
ModelPrivate *pModel;
+ Handle handle;
BusControl *control;
+ bool multiChannelOutput{};
};
Master::Master(Model *model) : QObject(model), d_ptr(new MasterPrivate) {
Q_D(Master);
d->q_ptr = this;
d->pModel = ModelPrivate::get(model);
+ d->handle = model->handle();
d->control = d->pModel->createObject(model->handle());
}
void Master::handleProxySetEntityProperty(int property, const QVariant &value) {
Q_D(Master);
- ModelPrivate::proxySetEntityPropertyNotify(d->control, property, value);
+ switch (property) {
+ case ModelStrategy::P_ControlGain:
+ case ModelStrategy::P_ControlPan:
+ case ModelStrategy::P_ControlMute: {
+ ModelPrivate::proxySetEntityPropertyNotify(d->control, property, value);
+ break;
+ }
+ case ModelStrategy::P_MultiChannelOutput: {
+ d->multiChannelOutput = value.toBool();
+ Q_EMIT multiChannelOutputChanged(d->multiChannelOutput);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ }
+
}
Master::~Master() = default;
@@ -35,16 +53,24 @@ namespace dspx {
Q_D(const Master);
return d->control;
}
+ bool Master::multiChannelOutput() const {
+ Q_D(const Master);
+ return d->multiChannelOutput;
+ }
+ void Master::setMultiChannelOutput(bool multiChannelOutput) {
+ Q_D(Master);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_MultiChannelOutput, multiChannelOutput);
+ }
- QDspx::Master Master::toQDspx() const {
+ opendspx::Master Master::toOpenDspx() const {
return {
- .control = control()->toQDspx(),
+ .control = control()->toOpenDspx(),
};
}
- void Master::fromQDspx(const QDspx::Master &master) {
+ void Master::fromOpenDspx(const opendspx::Master &master) {
Q_D(Master);
- d->control->fromQDspx(master.control);
+ d->control->fromOpenDspx(master.control);
}
}
diff --git a/src/libs/application/dspxmodel/src/Master.h b/src/libs/application/dspxmodel/src/Master.h
index 507ae783..8312a172 100644
--- a/src/libs/application/dspxmodel/src/Master.h
+++ b/src/libs/application/dspxmodel/src/Master.h
@@ -1,11 +1,12 @@
#ifndef DIFFSCOPE_DSPX_MODEL_MASTER_H
#define DIFFSCOPE_DSPX_MODEL_MASTER_H
+#include
#include
-#include
+#include
-namespace QDspx {
+namespace opendspx {
struct Master;
}
@@ -19,20 +20,26 @@ namespace dspx {
class MasterPrivate;
- class Master : public QObject {
+ class DSPX_MODEL_EXPORT Master : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(Master)
Q_PROPERTY(BusControl *control READ control CONSTANT)
-
+ Q_PROPERTY(bool multiChannelOutput READ multiChannelOutput WRITE setMultiChannelOutput NOTIFY multiChannelOutputChanged)
public:
~Master() override;
BusControl *control() const;
- QDspx::Master toQDspx() const;
- void fromQDspx(const QDspx::Master &master);
+ bool multiChannelOutput() const;
+ void setMultiChannelOutput(bool multiChannelOutput);
+
+ opendspx::Master toOpenDspx() const;
+ void fromOpenDspx(const opendspx::Master &master);
+
+ Q_SIGNALS:
+ void multiChannelOutputChanged(bool multiChannelOutput);
private:
friend class ModelPrivate;
diff --git a/src/libs/application/dspxmodel/src/Model.cpp b/src/libs/application/dspxmodel/src/Model.cpp
index a91105e0..2721a942 100644
--- a/src/libs/application/dspxmodel/src/Model.cpp
+++ b/src/libs/application/dspxmodel/src/Model.cpp
@@ -2,12 +2,15 @@
#include "Model_p.h"
#include
+#include
#include
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -29,6 +32,7 @@
#include
#include
#include
+#include
namespace dspx {
@@ -61,6 +65,7 @@ namespace dspx {
timeline = new Timeline(q);
labels = new LabelSequence(strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Labels), q);
+ keySignatures = new KeySignatureSequence(strategy->getAssociatedSubEntity(handle, ModelStrategy::R_KeySignatures), q);
tempos = new TempoSequence(strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Tempos), q);
timeSignatures = new TimeSignatureSequence(strategy->getAssociatedSubEntity(handle, ModelStrategy::R_TimeSignatures), q);
tracks = new TrackList(strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children), q);
@@ -90,6 +95,15 @@ namespace dspx {
}
});
+ QObject::connect(strategy, &ModelStrategy::moveToAnotherSequenceContainerNotified, q, [=, this](Handle sequenceContainerEntity, Handle entity, Handle otherSequenceContainerEntity) {
+ auto sequenceContainerObject = mapToObject(sequenceContainerEntity);
+ auto otherSequenceContainerObject = mapToObject(otherSequenceContainerEntity);
+ if (sequenceContainerObject && otherSequenceContainerObject) {
+ sequenceContainerObject->handleMoveToAnotherSequenceContainer(entity, otherSequenceContainerEntity);
+ otherSequenceContainerObject->handleMoveFromAnotherSequenceContainer(entity, sequenceContainerEntity);
+ }
+ });
+
QObject::connect(strategy, &ModelStrategy::takeFromContainerNotified, q, [=, this](Handle takenEntity, Handle sequenceContainerEntity, Handle entity) {
if (auto sequenceContainerObject = mapToObject(sequenceContainerEntity)) {
sequenceContainerObject->handleTakeFromSequenceContainer(takenEntity, entity);
@@ -209,26 +223,62 @@ namespace dspx {
return d->workspace;
}
- QDspx::Model Model::toQDspx() const {
- return {
- .version = QDspx::Model::V1,
+ opendspx::Model Model::toOpenDspx() const {
+ opendspx::Model model = {
+ .version = opendspx::Model::Version::V1,
.content = {
- .global = global()->toQDspx(),
- .master = master()->toQDspx(),
- .timeline = timeline()->toQDspx(),
- .tracks = tracks()->toQDspx(),
- .workspace = workspace()->toQDspx(),
+ .global = global()->toOpenDspx(),
+ .master = master()->toOpenDspx(),
+ .timeline = timeline()->toOpenDspx(),
+ .tracks = tracks()->toOpenDspx(),
+ .workspace = workspace()->toOpenDspx(),
}
};
+ model.content.workspace["diffscope"] = nlohmann::json::object({
+ {"loop", nlohmann::json{
+ {"enabled", timeline()->isLoopEnabled()},
+ {"start", timeline()->loopStart()},
+ {"length", timeline()->loopLength()},
+ }},
+ {"master", nlohmann::json{
+ {"multiChannelOutput", master()->multiChannelOutput()}
+ }},
+ {"keySignatures", timeline()->keySignatures()->toOpenDspx()}
+ });
+ return model;
}
- void Model::fromQDspx(const QDspx::Model &model) {
+ void Model::fromOpenDspx(const opendspx::Model &model) {
Q_D(Model);
- d->global->fromQDspx(model.content.global);
- d->master->fromQDspx(model.content.master);
- d->timeline->fromQDspx(model.content.timeline);
- d->tracks->fromQDspx(model.content.tracks);
- d->workspace->fromQDspx(model.content.workspace);
+ d->global->fromOpenDspx(model.content.global);
+ d->master->fromOpenDspx(model.content.master);
+ d->timeline->fromOpenDspx(model.content.timeline);
+ d->tracks->fromOpenDspx(model.content.tracks);
+ d->workspace->fromOpenDspx(model.content.workspace);
+ auto diffscopeWorkspace = !model.content.workspace.contains("diffscope") ? QJsonObject() : JsonUtils::toQJsonValue(model.content.workspace.at("diffscope")).toObject();
+ {
+ auto loop = diffscopeWorkspace.value("loop").toObject();
+ auto enabled = loop.value("enabled").toBool();
+ auto start = loop.value("start").toInt();
+ auto length = loop.value("length").toInt();
+ if (start < 0 || length <= 0) {
+ d->timeline->setLoopEnabled(false);
+ d->timeline->setLoopStart(0);
+ d->timeline->setLoopLength(1920);
+ } else {
+ d->timeline->setLoopEnabled(enabled);
+ d->timeline->setLoopStart(start);
+ d->timeline->setLoopLength(length);
+ }
+ }
+ {
+ auto master = diffscopeWorkspace.value("master").toObject();
+ d->master->setMultiChannelOutput(master.value("multiChannelOutput").toBool());
+ }
+ {
+ auto keySignatures = diffscopeWorkspace.value("keySignatures").toArray();
+ d->timeline->keySignatures()->fromOpenDspx(JsonUtils::fromQJsonValue(keySignatures));
+ }
}
Label *Model::createLabel() {
@@ -249,6 +299,12 @@ namespace dspx {
return d->createObject(handle);
}
+ KeySignature *Model::createKeySignature() {
+ Q_D(Model);
+ auto handle = d->strategy->createEntity(ModelStrategy::EI_KeySignature);
+ return d->createObject(handle);
+ }
+
Tempo *Model::createTempo() {
Q_D(Model);
auto handle = d->strategy->createEntity(ModelStrategy::EI_Tempo);
@@ -353,10 +409,17 @@ namespace dspx {
}
case ModelStrategy::P_ControlGain:
case ModelStrategy::P_ControlPan:
- case ModelStrategy::P_ControlMute: {
+ case ModelStrategy::P_ControlMute:
+ case ModelStrategy::P_MultiChannelOutput: {
ModelPrivate::proxySetEntityPropertyNotify(d->master, property, value);
break;
}
+ case ModelStrategy::P_LoopEnabled:
+ case ModelStrategy::P_LoopLength:
+ case ModelStrategy::P_LoopStart: {
+ ModelPrivate::proxySetEntityPropertyNotify(d->timeline, property, value);
+ break;
+ }
default:
Q_UNREACHABLE();
}
diff --git a/src/libs/application/dspxmodel/src/Model.h b/src/libs/application/dspxmodel/src/Model.h
index 02d762f2..73624131 100644
--- a/src/libs/application/dspxmodel/src/Model.h
+++ b/src/libs/application/dspxmodel/src/Model.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct Model;
}
@@ -23,6 +23,7 @@ namespace dspx {
class Label;
class Note;
class Phoneme;
+ class KeySignature;
class Tempo;
class TimeSignature;
class Track;
@@ -59,12 +60,13 @@ namespace dspx {
TrackList *tracks() const;
Workspace *workspace() const;
- QDspx::Model toQDspx() const;
- void fromQDspx(const QDspx::Model &model);
+ opendspx::Model toOpenDspx() const;
+ void fromOpenDspx(const opendspx::Model &model);
Q_INVOKABLE Label *createLabel();
Q_INVOKABLE Note *createNote();
Q_INVOKABLE Phoneme *createPhoneme();
+ Q_INVOKABLE KeySignature *createKeySignature();
Q_INVOKABLE Tempo *createTempo();
Q_INVOKABLE TimeSignature *createTimeSignature();
Q_INVOKABLE Track *createTrack();
diff --git a/src/libs/application/dspxmodel/src/ModelStrategy.h b/src/libs/application/dspxmodel/src/ModelStrategy.h
index 0a56fbfa..f9fb5dd8 100644
--- a/src/libs/application/dspxmodel/src/ModelStrategy.h
+++ b/src/libs/application/dspxmodel/src/ModelStrategy.h
@@ -19,6 +19,7 @@ namespace dspx {
enum Entity {
EI_AudioClip,
EI_Global,
+ EI_KeySignature,
EI_Label,
EI_Note,
EI_Param,
@@ -34,14 +35,15 @@ namespace dspx {
EI_WorkspaceInfo,
ES_Clips,
+ ES_KeySignatures,
ES_Labels,
ES_Notes,
ES_ParamCurveAnchorNodes,
ES_ParamCurves,
+ ES_Phonemes,
ES_Tempos,
ES_TimeSignatures,
- EL_Phonemes,
EL_Tracks,
ED_ParamCurveFreeValues,
@@ -53,6 +55,7 @@ namespace dspx {
};
enum Property {
+ P_AccidentalType,
P_Author,
P_CentShift,
P_ClipStart,
@@ -61,15 +64,22 @@ namespace dspx {
P_ControlGain,
P_ControlMute,
P_ControlPan,
+ P_ControlRecord,
P_ControlSolo,
P_Denominator,
P_EditorId,
P_EditorName,
+ P_Height,
P_JsonObject,
P_KeyNumber,
P_Language,
P_Length,
+ P_LoopEnabled,
+ P_LoopLength,
+ P_LoopStart,
P_Measure,
+ P_Mode,
+ P_MultiChannelOutput,
P_Name,
P_Numerator,
P_Onset,
@@ -78,6 +88,7 @@ namespace dspx {
P_PronunciationEdited,
P_PronunciationOriginal,
P_Text,
+ P_Tonality,
P_Type,
P_Value,
P_VibratoAmplitude,
@@ -90,6 +101,7 @@ namespace dspx {
enum Relationship {
R_Children,
+ R_KeySignatures,
R_Labels,
R_ParamCurvesEdited,
R_ParamCurvesOriginal,
@@ -132,6 +144,8 @@ namespace dspx {
virtual bool insertIntoListContainer(Handle listContainerEntity, Handle entity, int index) = 0;
virtual bool insertIntoMapContainer(Handle mapContainerEntity, Handle entity, const QString &key) = 0;
+ virtual bool moveToAnotherSequenceContainer(Handle sequenceContainerEntity, Handle entity, Handle otherSequenceContainerEntity) = 0;
+
virtual Handle takeFromSequenceContainer(Handle sequenceContainerEntity, Handle entity) = 0;
virtual Handle takeFromListContainer(Handle listContainerEntity, int index) = 0;
virtual Handle takeFromMapContainer(Handle mapContainerEntity, const QString &key) = 0;
@@ -155,6 +169,8 @@ namespace dspx {
void insertIntoListContainerNotified(Handle listContainerEntity, Handle entity, int index);
void insertIntoMapContainerNotified(Handle mapContainerEntity, Handle entity, const QString &key);
+ void moveToAnotherSequenceContainerNotified(Handle sequenceContainerEntity, Handle entity, Handle otherSequenceContainerEntity);
+
void takeFromContainerNotified(Handle takenEntity, Handle sequenceContainerEntity, Handle entity);
void takeFromListContainerNotified(Handle takenEntities, Handle listContainerEntity, int index);
void takeFromMapContainerNotified(Handle takenEntity, Handle mapContainerEntity, const QString &key);
@@ -183,6 +199,10 @@ namespace dspx {
if (entityType == EI_ParamCurveFree) {
return ED_ParamCurveFreeValues;
}
+ } else if (relationship == R_KeySignatures) {
+ if (entityType == EI_Global) {
+ return ES_KeySignatures;
+ }
} else if (relationship == R_Labels) {
if (entityType == EI_Global) {
return ES_Labels;
@@ -197,7 +217,7 @@ namespace dspx {
}
} else if (relationship == R_PhonemesEdited || relationship == R_PhonemesOriginal) {
if (entityType == EI_Note) {
- return EL_Phonemes;
+ return ES_Phonemes;
}
} else if (relationship == R_Sources) {
if (entityType == EI_SingingClip) {
@@ -228,6 +248,18 @@ namespace dspx {
auto v = value.toInt();
return v >= -50 && v <= 50;
};
+ static auto validateAccidentalType = [](const QVariant &value) {
+ auto v = value.toInt();
+ return v == 0 || v == 1;
+ };
+ static auto validateMode = [](const QVariant &value) {
+ auto v = value.toInt();
+ return v >= 0 && v <= 4095;
+ };
+ static auto validateTonality = [](const QVariant &value) {
+ auto v = value.toInt();
+ return v >= 0 && v <= 11;
+ };
static auto validatePan = [](const QVariant &value) {
auto v = value.toDouble();
return v >= -1 && v <= 1;
@@ -236,6 +268,10 @@ namespace dspx {
auto v = value.toInt();
return v >= 0;
};
+ static auto validateIntGreaterZero = [](const QVariant &value) {
+ auto v = value.toInt();
+ return v > 0;
+ };
static auto validateDoubleGreaterOrEqualZero = [](const QVariant &value) {
auto v = value.toDouble();
return v >= 0;
@@ -280,7 +316,17 @@ namespace dspx {
{P_EditorName, QMetaType::QString},
{P_ControlGain, QMetaType::Double},
{P_ControlPan, QMetaType::Double, validatePan},
- {P_ControlMute, QMetaType::Bool}
+ {P_ControlMute, QMetaType::Bool},
+ {P_MultiChannelOutput, QMetaType::Bool},
+ {P_LoopEnabled, QMetaType::Bool},
+ {P_LoopStart, QMetaType::Int, validateIntGreaterOrEqualZero},
+ {P_LoopLength, QMetaType::Int, validateIntGreaterZero},
+ };
+ case EI_KeySignature: return {
+ {P_Position, QMetaType::Int, validateIntGreaterOrEqualZero},
+ {P_Mode, QMetaType::Int, validateMode},
+ {P_Tonality, QMetaType::Int, validateTonality},
+ {P_AccidentalType, QMetaType::Int, validateAccidentalType}
};
case EI_Label: return {
{P_Position, QMetaType::Int, validateIntGreaterOrEqualZero},
@@ -348,7 +394,9 @@ namespace dspx {
{P_ControlGain, QMetaType::Double},
{P_ControlPan, QMetaType::Double, validatePan},
{P_ControlMute, QMetaType::Bool},
- {P_ControlSolo, QMetaType::Bool}
+ {P_ControlRecord, QMetaType::Bool},
+ {P_ControlSolo, QMetaType::Bool},
+ {P_Height, QMetaType::Double, validateDoubleGreaterOrEqualZero}
};
case EI_WorkspaceInfo: return {
{P_JsonObject, QMetaType::QJsonObject}
diff --git a/src/libs/application/dspxmodel/src/Model_p.h b/src/libs/application/dspxmodel/src/Model_p.h
index 4f65328a..4147afaf 100644
--- a/src/libs/application/dspxmodel/src/Model_p.h
+++ b/src/libs/application/dspxmodel/src/Model_p.h
@@ -8,6 +8,7 @@
namespace dspx {
class LabelSequence;
+ class KeySignatureSequence;
class TempoSequence;
class TimeSignatureSequence;
class Clip;
@@ -24,6 +25,7 @@ namespace dspx {
Timeline *timeline;
LabelSequence *labels;
+ KeySignatureSequence *keySignatures;
TempoSequence *tempos;
TimeSignatureSequence *timeSignatures;
TrackList *tracks;
@@ -61,18 +63,18 @@ namespace dspx {
return new T(handle, q);
}
- template <>
- Clip *createObject(Handle handle);
-
- template <>
- ParamCurve *createObject(Handle handle);
-
template
static void proxySetEntityPropertyNotify(T *object, int property, const QVariant &value) {
object->handleProxySetEntityProperty(property, value);
}
};
+ template <>
+ Clip *ModelPrivate::createObject(Handle handle);
+
+ template <>
+ ParamCurve *ModelPrivate::createObject(Handle handle);
+
}
#endif //DIFFSCOPE_DSPX_MODEL_MODEL_P_H
diff --git a/src/libs/application/dspxmodel/src/Note.cpp b/src/libs/application/dspxmodel/src/Note.cpp
index 9888c90c..88c2cf17 100644
--- a/src/libs/application/dspxmodel/src/Note.cpp
+++ b/src/libs/application/dspxmodel/src/Note.cpp
@@ -1,7 +1,5 @@
#include "Note.h"
#include "Note_p.h"
-
-#include
#include
#include
@@ -16,61 +14,7 @@
namespace dspx {
- void NotePrivate::setCentShiftUnchecked(int centShift_) {
- Q_Q(Note);
- pModel->strategy->setEntityProperty(q->handle(), ModelStrategy::P_CentShift, centShift_);
- }
-
- void NotePrivate::setCentShift(int centShift_) {
- Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && (centShift_ < -50 || centShift_ > 50)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("CentShift must be in range [-50, 50]"));
- return;
- }
- setCentShiftUnchecked(centShift_);
- }
- void NotePrivate::setKeyNumUnchecked(int keyNum_) {
- Q_Q(Note);
- pModel->strategy->setEntityProperty(q->handle(), ModelStrategy::P_KeyNumber, keyNum_);
- }
-
- void NotePrivate::setKeyNum(int keyNum_) {
- Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && (keyNum_ < 0 || keyNum_ > 127)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("KeyNum must be in range [0, 127]"));
- return;
- }
- setKeyNumUnchecked(keyNum_);
- }
-
- void NotePrivate::setLengthUnchecked(int length_) {
- Q_Q(Note);
- pModel->strategy->setEntityProperty(q->handle(), ModelStrategy::P_Length, length_);
- }
-
- void NotePrivate::setLength(int length_) {
- Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && length_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Length must be greater than or equal to 0"));
- return;
- }
- setLengthUnchecked(length_);
- }
-
- void NotePrivate::setPosUnchecked(int pos_) {
- Q_Q(Note);
- pModel->strategy->setEntityProperty(q->handle(), ModelStrategy::P_Position, pos_);
- }
-
- void NotePrivate::setPos(int pos_) {
- Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && pos_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater than or equal to 0"));
- return;
- }
- setPosUnchecked(pos_);
- }
void NotePrivate::setOverlapped(Note *item, bool overlapped) {
auto d = item->d_func();
@@ -88,6 +32,22 @@ namespace dspx {
}
}
+ void NotePrivate::setPreviousItem(Note *item, Note *previousItem) {
+ auto d = item->d_func();
+ if (d->previousItem != previousItem) {
+ d->previousItem = previousItem;
+ Q_EMIT item->previousItemChanged();
+ }
+ }
+
+ void NotePrivate::setNextItem(Note *item, Note *nextItem) {
+ auto d = item->d_func();
+ if (d->nextItem != nextItem) {
+ d->nextItem = nextItem;
+ Q_EMIT item->nextItemChanged();
+ }
+ }
+
Note::Note(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new NotePrivate) {
Q_D(Note);
Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_Note);
@@ -115,7 +75,7 @@ namespace dspx {
void Note::setCentShift(int centShift) {
Q_D(Note);
Q_ASSERT(centShift >= -50 && centShift <= 50);
- d->setCentShiftUnchecked(centShift);
+ d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_CentShift, centShift);
}
int Note::keyNum() const {
@@ -126,7 +86,7 @@ namespace dspx {
void Note::setKeyNum(int keyNum) {
Q_D(Note);
Q_ASSERT(keyNum >= 0 && keyNum <= 127);
- d->setKeyNumUnchecked(keyNum);
+ d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_KeyNumber, keyNum);
}
QString Note::language() const {
@@ -147,7 +107,7 @@ namespace dspx {
void Note::setLength(int length) {
Q_D(Note);
Q_ASSERT(length >= 0);
- d->setLengthUnchecked(length);
+ d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_Length, length);
}
QString Note::lyric() const {
@@ -173,7 +133,7 @@ namespace dspx {
void Note::setPos(int pos) {
Q_D(Note);
Q_ASSERT(pos >= 0);
- d->setPosUnchecked(pos);
+ d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_Position, pos);
}
Pronunciation *Note::pronunciation() const {
@@ -196,37 +156,47 @@ namespace dspx {
return d->noteSequence;
}
+ Note *Note::previousItem() const {
+ Q_D(const Note);
+ return d->previousItem;
+ }
+
+ Note *Note::nextItem() const {
+ Q_D(const Note);
+ return d->nextItem;
+ }
+
bool Note::isOverlapped() const {
Q_D(const Note);
return d->overlapped;
}
- QDspx::Note Note::toQDspx() const {
+ opendspx::Note Note::toOpenDspx() const {
return {
.pos = pos(),
.length = length(),
.keyNum = keyNum(),
.centShift = centShift(),
- .language = language(),
- .lyric = lyric(),
- .pronunciation = pronunciation()->toQDspx(),
- .phonemes = phonemes()->toQDspx(),
- .vibrato = vibrato()->toQDspx(),
- .workspace = workspace()->toQDspx(),
+ .language = language().toStdString(),
+ .lyric = lyric().toStdString(),
+ .pronunciation = pronunciation()->toOpenDspx(),
+ .phonemes = phonemes()->toOpenDspx(),
+ .vibrato = vibrato()->toOpenDspx(),
+ .workspace = workspace()->toOpenDspx(),
};
}
- void Note::fromQDspx(const QDspx::Note ¬e) {
+ void Note::fromOpenDspx(const opendspx::Note ¬e) {
setPos(note.pos);
setLength(note.length);
setKeyNum(note.keyNum);
setCentShift(note.centShift);
- setLanguage(note.language);
- setLyric(note.lyric);
- pronunciation()->fromQDspx(note.pronunciation);
- phonemes()->fromQDspx(note.phonemes);
- vibrato()->fromQDspx(note.vibrato);
- workspace()->fromQDspx(note.workspace);
+ setLanguage(QString::fromStdString(note.language));
+ setLyric(QString::fromStdString(note.lyric));
+ pronunciation()->fromOpenDspx(note.pronunciation);
+ phonemes()->fromOpenDspx(note.phonemes);
+ vibrato()->fromOpenDspx(note.vibrato);
+ workspace()->fromOpenDspx(note.workspace);
}
void Note::handleSetEntityProperty(int property, const QVariant &value) {
diff --git a/src/libs/application/dspxmodel/src/Note.h b/src/libs/application/dspxmodel/src/Note.h
index e96311d5..a7b076a1 100644
--- a/src/libs/application/dspxmodel/src/Note.h
+++ b/src/libs/application/dspxmodel/src/Note.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct Note;
}
@@ -26,17 +26,19 @@ namespace dspx {
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(Note)
- Q_PRIVATE_PROPERTY(d_func(), int centShift MEMBER centShift WRITE setCentShift NOTIFY centShiftChanged)
- Q_PRIVATE_PROPERTY(d_func(), int keyNum MEMBER keyNum WRITE setKeyNum NOTIFY keyNumChanged)
+ Q_PROPERTY(int centShift READ centShift WRITE setCentShift NOTIFY centShiftChanged)
+ Q_PROPERTY(int keyNum READ keyNum WRITE setKeyNum NOTIFY keyNumChanged)
Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged)
- Q_PRIVATE_PROPERTY(d_func(), int length MEMBER length WRITE setLength NOTIFY lengthChanged)
+ Q_PROPERTY(int length READ length WRITE setLength NOTIFY lengthChanged)
Q_PROPERTY(QString lyric READ lyric WRITE setLyric NOTIFY lyricChanged)
Q_PROPERTY(PhonemeInfo *phonemes READ phonemes CONSTANT)
- Q_PRIVATE_PROPERTY(d_func(), int pos MEMBER pos WRITE setPos NOTIFY posChanged)
+ Q_PROPERTY(int pos READ pos WRITE setPos NOTIFY posChanged)
Q_PROPERTY(Pronunciation *pronunciation READ pronunciation CONSTANT)
Q_PROPERTY(Vibrato *vibrato READ vibrato CONSTANT)
Q_PROPERTY(Workspace *workspace READ workspace CONSTANT)
Q_PROPERTY(NoteSequence *noteSequence READ noteSequence NOTIFY noteSequenceChanged)
+ Q_PROPERTY(Note *previousItem READ previousItem NOTIFY previousItemChanged)
+ Q_PROPERTY(Note *nextItem READ nextItem NOTIFY nextItemChanged)
Q_PROPERTY(bool overlapped READ isOverlapped NOTIFY overlappedChanged)
public:
@@ -70,10 +72,13 @@ namespace dspx {
NoteSequence *noteSequence() const;
+ Note *previousItem() const;
+ Note *nextItem() const;
+
bool isOverlapped() const;
- QDspx::Note toQDspx() const;
- void fromQDspx(const QDspx::Note ¬e);
+ opendspx::Note toOpenDspx() const;
+ void fromOpenDspx(const opendspx::Note ¬e);
Q_SIGNALS:
void centShiftChanged(int centShift);
@@ -83,6 +88,8 @@ namespace dspx {
void lyricChanged(const QString &lyric);
void posChanged(int pos);
void noteSequenceChanged();
+ void previousItemChanged();
+ void nextItemChanged();
void overlappedChanged(bool overlapped);
protected:
diff --git a/src/libs/application/dspxmodel/src/NoteSequence.cpp b/src/libs/application/dspxmodel/src/NoteSequence.cpp
index dd73d9c4..aa15b352 100644
--- a/src/libs/application/dspxmodel/src/NoteSequence.cpp
+++ b/src/libs/application/dspxmodel/src/NoteSequence.cpp
@@ -22,13 +22,6 @@ namespace dspx {
d->singingClip = singingClip;
d->init(model->strategy()->getEntitiesFromSequenceContainer(handle));
-
- connect(this, &NoteSequence::itemInserted, this, [=](Note *item) {
- NotePrivate::setNoteSequence(item, this);
- });
- connect(this, &NoteSequence::itemRemoved, this, [=](Note *item) {
- NotePrivate::setNoteSequence(item, nullptr);
- });
}
NoteSequence::~NoteSequence() = default;
@@ -83,22 +76,22 @@ namespace dspx {
return d->pModel->strategy->takeFromSequenceContainer(handle(), item->handle());
}
- QList NoteSequence::toQDspx() const {
+ std::vector NoteSequence::toOpenDspx() const {
Q_D(const NoteSequence);
- QList ret;
+ std::vector ret;
for (const auto &[_, item] : d->pointContainer.m_items) {
- ret.append(item->toQDspx());
+ ret.push_back(item->toOpenDspx());
}
return ret;
}
- void NoteSequence::fromQDspx(const QList ¬es) {
+ void NoteSequence::fromOpenDspx(const std::vector ¬es) {
while (size() > 0) {
removeItem(firstItem());
}
for (const auto ¬eData : notes) {
auto note = model()->createNote();
- note->fromQDspx(noteData);
+ note->fromOpenDspx(noteData);
insertItem(note);
}
}
diff --git a/src/libs/application/dspxmodel/src/NoteSequence.h b/src/libs/application/dspxmodel/src/NoteSequence.h
index 211c09ee..724b9c40 100644
--- a/src/libs/application/dspxmodel/src/NoteSequence.h
+++ b/src/libs/application/dspxmodel/src/NoteSequence.h
@@ -6,7 +6,7 @@
#include
#include
-namespace QDspx {
+namespace opendspx {
struct Note;
}
@@ -42,8 +42,8 @@ namespace dspx {
Q_INVOKABLE bool insertItem(Note *item);
Q_INVOKABLE bool removeItem(Note *item);
- QList toQDspx() const;
- void fromQDspx(const QList ¬es);
+ std::vector toOpenDspx() const;
+ void fromOpenDspx(const std::vector ¬es);
SingingClip *singingClip() const;
diff --git a/src/libs/application/dspxmodel/src/NoteSequence_p.h b/src/libs/application/dspxmodel/src/NoteSequence_p.h
index 950ff19b..1200cb50 100644
--- a/src/libs/application/dspxmodel/src/NoteSequence_p.h
+++ b/src/libs/application/dspxmodel/src/NoteSequence_p.h
@@ -8,7 +8,7 @@
namespace dspx {
- class NoteSequencePrivate : public RangeSequenceData {
+ class NoteSequencePrivate : public RangeSequenceData {
Q_DECLARE_PUBLIC(NoteSequence)
public:
SingingClip *singingClip{};
diff --git a/src/libs/application/dspxmodel/src/Note_p.h b/src/libs/application/dspxmodel/src/Note_p.h
index c6a70912..72d6865a 100644
--- a/src/libs/application/dspxmodel/src/Note_p.h
+++ b/src/libs/application/dspxmodel/src/Note_p.h
@@ -22,19 +22,14 @@ namespace dspx {
Vibrato *vibrato;
Workspace *workspace;
NoteSequence *noteSequence{};
+ Note *previousItem{};
+ Note *nextItem{};
bool overlapped{};
- void setCentShiftUnchecked(int centShift_);
- void setCentShift(int centShift_);
- void setKeyNumUnchecked(int keyNum_);
- void setKeyNum(int keyNum_);
- void setLengthUnchecked(int length_);
- void setLength(int length_);
- void setPosUnchecked(int pos_);
- void setPos(int pos_);
-
static void setOverlapped(Note *item, bool overlapped);
static void setNoteSequence(Note *item, NoteSequence *noteSequence);
+ static void setPreviousItem(Note *item, Note *previousItem);
+ static void setNextItem(Note *item, Note *nextItem);
};
}
diff --git a/src/libs/application/dspxmodel/src/Param.cpp b/src/libs/application/dspxmodel/src/Param.cpp
index b81c7f12..76a5a2b7 100644
--- a/src/libs/application/dspxmodel/src/Param.cpp
+++ b/src/libs/application/dspxmodel/src/Param.cpp
@@ -47,20 +47,20 @@ namespace dspx {
return d->edited;
}
- QDspx::Param Param::toQDspx() const {
+ opendspx::Param Param::toOpenDspx() const {
Q_D(const Param);
return {
- .original = d->original->toQDspx(),
- .transform = d->transform->toQDspx(),
- .edited = d->edited->toQDspx(),
+ .original = d->original->toOpenDspx(),
+ .transform = d->transform->toOpenDspx(),
+ .edited = d->edited->toOpenDspx(),
};
}
- void Param::fromQDspx(const QDspx::Param ¶m) {
+ void Param::fromOpenDspx(const opendspx::Param ¶m) {
Q_D(Param);
- d->original->fromQDspx(param.original);
- d->transform->fromQDspx(param.transform);
- d->edited->fromQDspx(param.edited);
+ d->original->fromOpenDspx(param.original);
+ d->transform->fromOpenDspx(param.transform);
+ d->edited->fromOpenDspx(param.edited);
}
ParamMap *Param::paramMap() const {
diff --git a/src/libs/application/dspxmodel/src/Param.h b/src/libs/application/dspxmodel/src/Param.h
index dbb04407..cc80a1d3 100644
--- a/src/libs/application/dspxmodel/src/Param.h
+++ b/src/libs/application/dspxmodel/src/Param.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct Param;
}
@@ -34,8 +34,8 @@ namespace dspx {
ParamMap *paramMap() const;
- QDspx::Param toQDspx() const;
- void fromQDspx(const QDspx::Param ¶m);
+ opendspx::Param toOpenDspx() const;
+ void fromOpenDspx(const opendspx::Param ¶m);
Q_SIGNALS:
void paramMapChanged();
diff --git a/src/libs/application/dspxmodel/src/ParamCurve.cpp b/src/libs/application/dspxmodel/src/ParamCurve.cpp
index 1da88780..0e7ead04 100644
--- a/src/libs/application/dspxmodel/src/ParamCurve.cpp
+++ b/src/libs/application/dspxmodel/src/ParamCurve.cpp
@@ -22,6 +22,22 @@ namespace dspx {
Q_EMIT paramCurve->paramCurveSequenceChanged();
}
+ void ParamCurvePrivate::setPreviousItem(ParamCurve *paramCurve, ParamCurve *previousItem) {
+ auto d = paramCurve->d_func();
+ if (d->previousItem != previousItem) {
+ d->previousItem = previousItem;
+ Q_EMIT paramCurve->previousItemChanged();
+ }
+ }
+
+ void ParamCurvePrivate::setNextItem(ParamCurve *paramCurve, ParamCurve *nextItem) {
+ auto d = paramCurve->d_func();
+ if (d->nextItem != nextItem) {
+ d->nextItem = nextItem;
+ Q_EMIT paramCurve->nextItemChanged();
+ }
+ }
+
ParamCurve::ParamCurve(CurveType type, Handle handle, Model *model)
: EntityObject(handle, model), d_ptr(new ParamCurvePrivate) {
Q_D(ParamCurve);
@@ -53,25 +69,35 @@ namespace dspx {
return d->paramCurveSequence;
}
- QDspx::ParamCurveRef ParamCurve::toQDspx() const {
+ ParamCurve *ParamCurve::previousItem() const {
+ Q_D(const ParamCurve);
+ return d->previousItem;
+ }
+
+ ParamCurve *ParamCurve::nextItem() const {
+ Q_D(const ParamCurve);
+ return d->nextItem;
+ }
+
+ opendspx::ParamCurveRef ParamCurve::toOpenDspx() const {
Q_D(const ParamCurve);
switch (d->type) {
case Anchor:
- return QSharedPointer::create(static_cast(this)->toQDspx());
+ return std::make_shared(static_cast(this)->toOpenDspx());
case Free:
- return QSharedPointer::create(static_cast(this)->toQDspx());
+ return std::make_shared(static_cast(this)->toOpenDspx());
default:
Q_UNREACHABLE();
}
}
- void ParamCurve::fromQDspx(const QDspx::ParamCurveRef &curve) {
+ void ParamCurve::fromOpenDspx(const opendspx::ParamCurveRef &curve) {
switch (curve->type) {
- case QDspx::ParamCurve::Anchor:
- static_cast(this)->fromQDspx(*curve.staticCast());
+ case opendspx::ParamCurve::Anchor:
+ static_cast(this)->fromOpenDspx(*std::static_pointer_cast(curve));
break;
- case QDspx::ParamCurve::Free:
- static_cast(this)->fromQDspx(*curve.staticCast());
+ case opendspx::ParamCurve::Free:
+ static_cast(this)->fromOpenDspx(*std::static_pointer_cast(curve));
break;
default:
Q_UNREACHABLE();
diff --git a/src/libs/application/dspxmodel/src/ParamCurve.h b/src/libs/application/dspxmodel/src/ParamCurve.h
index 7cff8619..6eb4a00b 100644
--- a/src/libs/application/dspxmodel/src/ParamCurve.h
+++ b/src/libs/application/dspxmodel/src/ParamCurve.h
@@ -5,9 +5,9 @@
#include
-namespace QDspx {
+namespace opendspx {
struct ParamCurve;
- using ParamCurveRef = QSharedPointer;
+ using ParamCurveRef = std::shared_ptr;
}
namespace dspx {
@@ -23,6 +23,8 @@ namespace dspx {
Q_PROPERTY(int start READ start WRITE setStart NOTIFY startChanged)
Q_PROPERTY(CurveType type READ type CONSTANT)
Q_PROPERTY(ParamCurveSequence *paramCurveSequence READ paramCurveSequence NOTIFY paramCurveSequenceChanged)
+ Q_PROPERTY(ParamCurve *previousItem READ previousItem NOTIFY previousItemChanged)
+ Q_PROPERTY(ParamCurve *nextItem READ nextItem NOTIFY nextItemChanged)
public:
enum CurveType {
@@ -40,12 +42,17 @@ namespace dspx {
ParamCurveSequence *paramCurveSequence() const;
- QDspx::ParamCurveRef toQDspx() const;
- void fromQDspx(const QDspx::ParamCurveRef &curve);
+ ParamCurve *previousItem() const;
+ ParamCurve *nextItem() const;
+
+ opendspx::ParamCurveRef toOpenDspx() const;
+ void fromOpenDspx(const opendspx::ParamCurveRef &curve);
Q_SIGNALS:
void startChanged(int start);
void paramCurveSequenceChanged();
+ void previousItemChanged();
+ void nextItemChanged();
protected:
explicit ParamCurve(CurveType type, Handle handle, Model *model);
diff --git a/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp b/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp
index 7e2bd226..8545bec6 100644
--- a/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp
+++ b/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp
@@ -33,16 +33,16 @@ namespace dspx {
return d->nodes;
}
- QDspx::ParamCurveAnchor ParamCurveAnchor::toQDspx() const {
+ opendspx::ParamCurveAnchor ParamCurveAnchor::toOpenDspx() const {
return {
start(),
- nodes()->toQDspx(),
+ nodes()->toOpenDspx(),
};
}
- void ParamCurveAnchor::fromQDspx(const QDspx::ParamCurveAnchor &curve) {
+ void ParamCurveAnchor::fromOpenDspx(const opendspx::ParamCurveAnchor &curve) {
setStart(curve.start);
- nodes()->fromQDspx(curve.nodes);
+ nodes()->fromOpenDspx(curve.nodes);
}
void ParamCurveAnchor::handleSetEntityProperty(int property, const QVariant &value) {
diff --git a/src/libs/application/dspxmodel/src/ParamCurveAnchor.h b/src/libs/application/dspxmodel/src/ParamCurveAnchor.h
index a315e057..bc72aa80 100644
--- a/src/libs/application/dspxmodel/src/ParamCurveAnchor.h
+++ b/src/libs/application/dspxmodel/src/ParamCurveAnchor.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct ParamCurveAnchor;
}
@@ -26,8 +26,8 @@ namespace dspx {
AnchorNodeSequence *nodes() const;
- QDspx::ParamCurveAnchor toQDspx() const;
- void fromQDspx(const QDspx::ParamCurveAnchor &curve);
+ opendspx::ParamCurveAnchor toOpenDspx() const;
+ void fromOpenDspx(const opendspx::ParamCurveAnchor &curve);
protected:
void handleSetEntityProperty(int property, const QVariant &value) override;
diff --git a/src/libs/application/dspxmodel/src/ParamCurveFree.cpp b/src/libs/application/dspxmodel/src/ParamCurveFree.cpp
index ed94fdb1..23681125 100644
--- a/src/libs/application/dspxmodel/src/ParamCurveFree.cpp
+++ b/src/libs/application/dspxmodel/src/ParamCurveFree.cpp
@@ -38,18 +38,18 @@ namespace dspx {
return d->values;
}
- QDspx::ParamCurveFree ParamCurveFree::toQDspx() const {
+ opendspx::ParamCurveFree ParamCurveFree::toOpenDspx() const {
Q_D(const ParamCurveFree);
return {
start(),
5,
- values()->toQDspx(),
+ values()->toOpenDspx(),
};
}
- void ParamCurveFree::fromQDspx(const QDspx::ParamCurveFree &curve) {
+ void ParamCurveFree::fromOpenDspx(const opendspx::ParamCurveFree &curve) {
setStart(curve.start);
- values()->fromQDspx(curve.values);
+ values()->fromOpenDspx(curve.values);
}
void ParamCurveFree::handleSetEntityProperty(int property, const QVariant &value) {
diff --git a/src/libs/application/dspxmodel/src/ParamCurveFree.h b/src/libs/application/dspxmodel/src/ParamCurveFree.h
index 9561ef1b..5ea7675c 100644
--- a/src/libs/application/dspxmodel/src/ParamCurveFree.h
+++ b/src/libs/application/dspxmodel/src/ParamCurveFree.h
@@ -5,7 +5,7 @@
#include
-namespace QDspx {
+namespace opendspx {
struct ParamCurveFree;
}
@@ -28,8 +28,8 @@ namespace dspx {
int step() const;
FreeValueDataArray *values() const;
- QDspx::ParamCurveFree toQDspx() const;
- void fromQDspx(const QDspx::ParamCurveFree &curve);
+ opendspx::ParamCurveFree toOpenDspx() const;
+ void fromOpenDspx(const opendspx::ParamCurveFree &curve);
protected:
void handleSetEntityProperty(int property, const QVariant &value) override;
diff --git a/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp b/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp
index 2ad19e7f..b0c5f3f6 100644
--- a/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp
+++ b/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp
@@ -27,13 +27,6 @@ namespace dspx {
d->param = param;
d->init(model->strategy()->getEntitiesFromSequenceContainer(handle));
-
- connect(this, &ParamCurveSequence::itemInserted, this, [this](ParamCurve *paramCurve) {
- ParamCurvePrivate::setParamCurveSequence(paramCurve, this);
- });
- connect(this, &ParamCurveSequence::itemRemoved, this, [this](ParamCurve *paramCurve) {
- ParamCurvePrivate::setParamCurveSequence(paramCurve, nullptr);
- });
}
ParamCurveSequence::~ParamCurveSequence() = default;
@@ -83,33 +76,33 @@ namespace dspx {
return d->pModel->strategy->takeFromSequenceContainer(handle(), item->handle());
}
- QList ParamCurveSequence::toQDspx() const {
+ std::vector ParamCurveSequence::toOpenDspx() const {
Q_D(const ParamCurveSequence);
- QList ret;
+ std::vector ret;
ret.reserve(d->container.size());
for (const auto &[_, item] : d->container.m_items) {
- ret.append(item->toQDspx());
+ ret.push_back(item->toOpenDspx());
}
return ret;
}
- void ParamCurveSequence::fromQDspx(const QList &curves) {
+ void ParamCurveSequence::fromOpenDspx(const std::vector &curves) {
while (size()) {
removeItem(firstItem());
}
for (const auto &curve : curves) {
ParamCurve *item = nullptr;
switch (curve->type) {
- case QDspx::ParamCurve::Anchor:
+ case opendspx::ParamCurve::Anchor:
item = model()->createParamCurveAnchor();
break;
- case QDspx::ParamCurve::Free:
+ case opendspx::ParamCurve::Free:
item = model()->createParamCurveFree();
break;
default:
Q_UNREACHABLE();
}
- item->fromQDspx(curve);
+ item->fromOpenDspx(curve);
insertItem(item);
}
}
diff --git a/src/libs/application/dspxmodel/src/ParamCurveSequence.h b/src/libs/application/dspxmodel/src/ParamCurveSequence.h
index b19c69f8..817b395d 100644
--- a/src/libs/application/dspxmodel/src/ParamCurveSequence.h
+++ b/src/libs/application/dspxmodel/src/ParamCurveSequence.h
@@ -6,9 +6,9 @@
#include
#include
-namespace QDspx {
+namespace opendspx {
struct ParamCurve;
- using ParamCurveRef = QSharedPointer;
+ using ParamCurveRef = std::shared_ptr;
}
namespace dspx {
@@ -42,8 +42,8 @@ namespace dspx {
Q_INVOKABLE bool insertItem(ParamCurve *item);
Q_INVOKABLE bool removeItem(ParamCurve *item);
- QList toQDspx() const;
- void fromQDspx(const QList &curves);
+ std::vector toOpenDspx() const;
+ void fromOpenDspx(const std::vector &curves);
Param *param() const;
diff --git a/src/libs/application/dspxmodel/src/ParamCurveSequence_p.h b/src/libs/application/dspxmodel/src/ParamCurveSequence_p.h
index 8ffb2c96..e7ee2b0f 100644
--- a/src/libs/application/dspxmodel/src/ParamCurveSequence_p.h
+++ b/src/libs/application/dspxmodel/src/ParamCurveSequence_p.h
@@ -8,7 +8,7 @@
namespace dspx {
- class ParamCurveSequencePrivate : public PointSequenceData {
+ class ParamCurveSequencePrivate : public PointSequenceData {
Q_DECLARE_PUBLIC(ParamCurveSequence)
public:
Param *param{};
diff --git a/src/libs/application/dspxmodel/src/ParamCurve_p.h b/src/libs/application/dspxmodel/src/ParamCurve_p.h
index f8478651..d8ceb1ee 100644
--- a/src/libs/application/dspxmodel/src/ParamCurve_p.h
+++ b/src/libs/application/dspxmodel/src/ParamCurve_p.h
@@ -16,8 +16,12 @@ namespace dspx {
ParamCurve::CurveType type;
int start{};
ParamCurveSequence *paramCurveSequence{};
+ ParamCurve *previousItem{};
+ ParamCurve *nextItem{};
static void setParamCurveSequence(ParamCurve *item, ParamCurveSequence *paramCurveSequence);
+ static void setPreviousItem(ParamCurve *item, ParamCurve *previousItem);
+ static void setNextItem(ParamCurve *item, ParamCurve *nextItem);
};
}
diff --git a/src/libs/application/dspxmodel/src/ParamMap.cpp b/src/libs/application/dspxmodel/src/ParamMap.cpp
index e9537f23..0a981537 100644
--- a/src/libs/application/dspxmodel/src/ParamMap.cpp
+++ b/src/libs/application/dspxmodel/src/ParamMap.cpp
@@ -1,7 +1,7 @@
#include "ModelStrategy.h"
#include "ParamMap.h"
-#include
+#include
#include
#include
@@ -72,23 +72,23 @@ namespace dspx {
return d->contains(key);
}
- QDspx::Params ParamMap::toQDspx() const {
+ opendspx::Params ParamMap::toOpenDspx() const {
Q_D(const ParamMap);
- QDspx::Params ret;
+ opendspx::Params ret;
for (const auto &[key, value] : d->itemMap.asKeyValueRange()) {
- ret.insert(key, value->toQDspx());
+ ret.insert({key.toStdString(), value->toOpenDspx()});
}
return ret;
}
- void ParamMap::fromQDspx(const QDspx::Params ¶mMap) {
+ void ParamMap::fromOpenDspx(const opendspx::Params ¶mMap) {
for (const auto &key : keys()) {
removeItem(key);
}
- for (const auto &[key, value] : paramMap.asKeyValueRange()) {
+ for (const auto &[key, value] : paramMap) {
auto param = model()->createParam();
- param->fromQDspx(value);
- insertItem(key, param);
+ param->fromOpenDspx(value);
+ insertItem(QString::fromStdString(key), param);
}
}
diff --git a/src/libs/application/dspxmodel/src/ParamMap.h b/src/libs/application/dspxmodel/src/ParamMap.h
index 0338d524..af9c679c 100644
--- a/src/libs/application/dspxmodel/src/ParamMap.h
+++ b/src/libs/application/dspxmodel/src/ParamMap.h
@@ -5,9 +5,8 @@
#include
-namespace QDspx {
- struct Param;
- using Params = QMap;
+namespace opendspx {
+ class Params;
}
namespace dspx {
@@ -38,8 +37,8 @@ namespace dspx {
Q_INVOKABLE Param *item(const QString &key) const;
Q_INVOKABLE bool contains(const QString &key) const;
- QDspx::Params toQDspx() const;
- void fromQDspx(const QDspx::Params ¶mMap);
+ opendspx::Params toOpenDspx() const;
+ void fromOpenDspx(const opendspx::Params ¶mMap);
SingingClip *singingClip() const;
diff --git a/src/libs/application/dspxmodel/src/Phoneme.cpp b/src/libs/application/dspxmodel/src/Phoneme.cpp
index 32f6e792..4b34dd0f 100644
--- a/src/libs/application/dspxmodel/src/Phoneme.cpp
+++ b/src/libs/application/dspxmodel/src/Phoneme.cpp
@@ -8,16 +8,32 @@
#include