diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 788f8d4726..62c5702b52 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,15 +16,15 @@ jobs: runs-on: ubuntu-latest steps: - name: normal check out repo - if: inputs.build-type != 'nightly' && inputs.build-type != 'beta' + if: inputs.build-type != 'nightly' && inputs.build-type != 'rc' uses: actions/checkout@v3 - name: nightly check out repo if: inputs.build-type == 'nightly' uses: actions/checkout@v3 with: ref: 'community' - - name: beta check out repo - if: inputs.build-type == 'beta' + - name: rc check out repo + if: inputs.build-type == 'rc' uses: actions/checkout@v3 with: ref: 'release/1.0' @@ -82,19 +82,19 @@ jobs: asset_name: deluge-nightly.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash asset_content_type: application/zip # required by GitHub API max_releases: 30 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted - - name: Create beta archive - if: inputs.build-type == 'beta' + - name: Create rc archive + if: inputs.build-type == 'rc' run: | - zip -j ./beta.zip build/Release/deluge*.bin - - name: Deploy beta zip to releases - if: inputs.build-type == 'beta' + zip -j ./rc.zip build/Release/deluge*.bin + - name: Deploy rc zip to releases + if: inputs.build-type == 'rc' uses: WebFreak001/deploy-nightly@v2.0.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions with: upload_url: https://uploads.github.com/repos/SynthstromAudible/DelugeFirmware/releases/123368988/assets{?name,label} # find out this value by opening https://api.github.com/repos///releases in your browser and copy the full "upload_url" value including the {?name,label} part release_id: 123368988 # same as above (id can just be taken out the upload_url, it's used to find old releases) - asset_path: ./beta.zip # path to archive to upload - asset_name: deluge-beta.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash + asset_path: ./rc.zip # path to archive to upload + asset_name: deluge-rc.zip # name to upload the release as, use $$ to insert date (YYYYMMDD) and 6 letter commit hash asset_content_type: application/zip # required by GitHub API max_releases: 30 # optional, if there are more releases than this matching the asset_name, the oldest ones are going to be deleted diff --git a/.github/workflows/beta-build.yml b/.github/workflows/rc-build.yml similarity index 83% rename from .github/workflows/beta-build.yml rename to .github/workflows/rc-build.yml index c847dbcdb9..c3d9ea9cc3 100644 --- a/.github/workflows/beta-build.yml +++ b/.github/workflows/rc-build.yml @@ -1,4 +1,4 @@ -name: Beta Build +name: RC Build on: workflow_dispatch: # allows manual triggering @@ -12,8 +12,8 @@ on: - 'release/1.0' jobs: - beta-build: + rc-build: uses: ./.github/workflows/build.yml with: firmware-retention-days: 30 - build-type: 'beta' + build-type: 'rc' diff --git a/.gitignore b/.gitignore index cffb749050..3bb8c48b2c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ __pycache__ /tests/RunAllTests /tests/_deps/* *.a +*.jdebug.user diff --git a/contrib/debug/Debug.jdebug b/contrib/debug/Debug.jdebug new file mode 100644 index 0000000000..b7b86ecaf5 --- /dev/null +++ b/contrib/debug/Debug.jdebug @@ -0,0 +1,334 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** + +File : C:/Data/Downloads/Deluge.jdebug +Created : 29 Sep 2023 10:11 +Ozone Version : V3.30b +*/ + +/********************************************************************* +* +* OnProjectLoad +* +* Function description +* Project load routine. Required. +* +********************************************************************** +*/ +void OnProjectLoad (void) { + // + // Dialog-generated settings + // + Project.AddPathSubstitute ("C:/Data/Downloads", "$(ProjectDir)"); + Project.AddPathSubstitute ("c:/data/downloads", "$(ProjectDir)"); + Project.SetTraceSource ("Trace Buffer"); + Project.SetDevice ("R7S721020"); + Project.SetHostIF ("USB", "600000832"); + Project.SetTargetIF ("SWD"); + Project.SetTIFSpeed ("4 MHz"); + Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-A9.svd"); + // + // User settings + // + Edit.Preference (PREF_TIMESTAMP_FORMAT, TIMESTAMP_FORMAT_INST_CNT); + File.Open ("../../build/Debug/deluge.elf"); + Edit.SysVar (VAR_TRACE_CORE_CLOCK, 400000000); +} + +/********************************************************************* +* +* OnStartupComplete +* +* Function description +* Called when program execution has reached/passed +* the startup completion point. Optional. +* +********************************************************************** +*/ +//void OnStartupComplete (void) { +//} + +/********************************************************************* +* +* TargetReset +* +* Function description +* Replaces the default target device reset routine. Optional. +* +* Notes +* This example demonstrates the usage when +* debugging an application in RAM on a Cortex-M target device. +* +********************************************************************** +*/ +//void TargetReset (void) { +// +// unsigned int SP; +// unsigned int PC; +// unsigned int VectorTableAddr; +// +// VectorTableAddr = Elf.GetBaseAddr(); +// // +// // Set up initial stack pointer +// // +// if (VectorTableAddr != 0xFFFFFFFF) { +// SP = Target.ReadU32(VectorTableAddr); +// Target.SetReg("SP", SP); +// } +// // +// // Set up entry point PC +// // +// PC = Elf.GetEntryPointPC(); +// +// if (PC != 0xFFFFFFFF) { +// Target.SetReg("PC", PC); +// } else if (VectorTableAddr != 0xFFFFFFFF) { +// PC = Target.ReadU32(VectorTableAddr + 4); +// Target.SetReg("PC", PC); +// } else { +// Util.Error("Project file error: failed to set entry point PC", 1); +// } +//} + +/********************************************************************* +* +* BeforeTargetReset +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetReset (void) { +//} + +/********************************************************************* +* +* AfterTargetReset +* +* Function description +* Event handler routine. Optional. +* The default implementation initializes SP and PC to reset values. +** +********************************************************************** +*/ +void AfterTargetReset (void) { + _SetupTarget(); +} + +/********************************************************************* +* +* DebugStart +* +* Function description +* Replaces the default debug session startup routine. Optional. +* +********************************************************************** +*/ +//void DebugStart (void) { +//} + +/********************************************************************* +* +* TargetConnect +* +* Function description +* Replaces the default target IF connection routine. Optional. +* +********************************************************************** +*/ +//void TargetConnect (void) { +//} + +/********************************************************************* +* +* BeforeTargetConnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetConnect (void) { +//} + +/********************************************************************* +* +* AfterTargetConnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetConnect (void) { +//} + +/********************************************************************* +* +* TargetDownload +* +* Function description +* Replaces the default program download routine. Optional. +* +********************************************************************** +*/ +//void TargetDownload (void) { +//} + +/********************************************************************* +* +* BeforeTargetDownload +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetDownload (void) { +//} + +/********************************************************************* +* +* AfterTargetDownload +* +* Function description +* Event handler routine. Optional. +* The default implementation initializes SP and PC to reset values. +* +********************************************************************** +*/ +void AfterTargetDownload (void) { + _SetupTarget(); +} + +/********************************************************************* +* +* BeforeTargetDisconnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetDisconnect (void) { +//} + +/********************************************************************* +* +* AfterTargetDisconnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetDisconnect (void) { +//} + +/********************************************************************* +* +* AfterTargetHalt +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetHalt (void) { +//} + +/********************************************************************* +* +* BeforeTargetResume +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetResume (void) { +//} + +/********************************************************************* +* +* OnSnapshotLoad +* +* Function description +* Called upon loading a snapshot. Optional. +* +* Additional information +* This function is used to restore the target state in cases +* where values cannot simply be written to the target. +* Typical use: GPIO clock needs to be enabled, before +* GPIO is configured. +* +********************************************************************** +*/ +//void OnSnapshotLoad (void) { +//} + +/********************************************************************* +* +* OnSnapshotSave +* +* Function description +* Called upon saving a snapshot. Optional. +* +* Additional information +* This function is usually used to save values of the target +* state which can either not be trivially read, +* or need to be restored in a specific way or order. +* Typically use: Memory Mapped Registers, +* such as PLL and GPIO configuration. +* +********************************************************************** +*/ +//void OnSnapshotSave (void) { +//} + +/********************************************************************* +* +* OnError +* +* Function description +* Called when an error ocurred. Optional. +* +********************************************************************** +*/ +//void OnError (void) { +//} + +/********************************************************************* +* +* AfterProjectLoad +* +* Function description +* After Project load routine. Optional. +* +********************************************************************** +*/ +//void AfterProjectLoad (void) { +//} + +/********************************************************************* +* +* _SetupTarget +* +* Function description +* Setup the target. +* Called by AfterTargetReset() and AfterTargetDownload(). +* +* Auto-generated function. May be overridden by Ozone. +* +********************************************************************** +*/ +void _SetupTarget(void) { + // + // this function is intentionally empty because both inital PC and + // initial SP were chosen not to be set + // +} diff --git a/contrib/debug/RelWithDebInfo.jdebug b/contrib/debug/RelWithDebInfo.jdebug new file mode 100644 index 0000000000..defc3379be --- /dev/null +++ b/contrib/debug/RelWithDebInfo.jdebug @@ -0,0 +1,334 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** + +File : C:/Data/Downloads/Deluge.jdebug +Created : 29 Sep 2023 10:11 +Ozone Version : V3.30b +*/ + +/********************************************************************* +* +* OnProjectLoad +* +* Function description +* Project load routine. Required. +* +********************************************************************** +*/ +void OnProjectLoad (void) { + // + // Dialog-generated settings + // + Project.AddPathSubstitute ("C:/Data/Downloads", "$(ProjectDir)"); + Project.AddPathSubstitute ("c:/data/downloads", "$(ProjectDir)"); + Project.SetTraceSource ("Trace Buffer"); + Project.SetDevice ("R7S721020"); + Project.SetHostIF ("USB", "600000832"); + Project.SetTargetIF ("SWD"); + Project.SetTIFSpeed ("4 MHz"); + Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-A9.svd"); + // + // User settings + // + Edit.Preference (PREF_TIMESTAMP_FORMAT, TIMESTAMP_FORMAT_INST_CNT); + File.Open ("../../build/RelWithDebInfo/deluge.elf"); + Edit.SysVar (VAR_TRACE_CORE_CLOCK, 400000000); +} + +/********************************************************************* +* +* OnStartupComplete +* +* Function description +* Called when program execution has reached/passed +* the startup completion point. Optional. +* +********************************************************************** +*/ +//void OnStartupComplete (void) { +//} + +/********************************************************************* +* +* TargetReset +* +* Function description +* Replaces the default target device reset routine. Optional. +* +* Notes +* This example demonstrates the usage when +* debugging an application in RAM on a Cortex-M target device. +* +********************************************************************** +*/ +//void TargetReset (void) { +// +// unsigned int SP; +// unsigned int PC; +// unsigned int VectorTableAddr; +// +// VectorTableAddr = Elf.GetBaseAddr(); +// // +// // Set up initial stack pointer +// // +// if (VectorTableAddr != 0xFFFFFFFF) { +// SP = Target.ReadU32(VectorTableAddr); +// Target.SetReg("SP", SP); +// } +// // +// // Set up entry point PC +// // +// PC = Elf.GetEntryPointPC(); +// +// if (PC != 0xFFFFFFFF) { +// Target.SetReg("PC", PC); +// } else if (VectorTableAddr != 0xFFFFFFFF) { +// PC = Target.ReadU32(VectorTableAddr + 4); +// Target.SetReg("PC", PC); +// } else { +// Util.Error("Project file error: failed to set entry point PC", 1); +// } +//} + +/********************************************************************* +* +* BeforeTargetReset +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetReset (void) { +//} + +/********************************************************************* +* +* AfterTargetReset +* +* Function description +* Event handler routine. Optional. +* The default implementation initializes SP and PC to reset values. +** +********************************************************************** +*/ +void AfterTargetReset (void) { + _SetupTarget(); +} + +/********************************************************************* +* +* DebugStart +* +* Function description +* Replaces the default debug session startup routine. Optional. +* +********************************************************************** +*/ +//void DebugStart (void) { +//} + +/********************************************************************* +* +* TargetConnect +* +* Function description +* Replaces the default target IF connection routine. Optional. +* +********************************************************************** +*/ +//void TargetConnect (void) { +//} + +/********************************************************************* +* +* BeforeTargetConnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetConnect (void) { +//} + +/********************************************************************* +* +* AfterTargetConnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetConnect (void) { +//} + +/********************************************************************* +* +* TargetDownload +* +* Function description +* Replaces the default program download routine. Optional. +* +********************************************************************** +*/ +//void TargetDownload (void) { +//} + +/********************************************************************* +* +* BeforeTargetDownload +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetDownload (void) { +//} + +/********************************************************************* +* +* AfterTargetDownload +* +* Function description +* Event handler routine. Optional. +* The default implementation initializes SP and PC to reset values. +* +********************************************************************** +*/ +void AfterTargetDownload (void) { + _SetupTarget(); +} + +/********************************************************************* +* +* BeforeTargetDisconnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetDisconnect (void) { +//} + +/********************************************************************* +* +* AfterTargetDisconnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetDisconnect (void) { +//} + +/********************************************************************* +* +* AfterTargetHalt +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetHalt (void) { +//} + +/********************************************************************* +* +* BeforeTargetResume +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetResume (void) { +//} + +/********************************************************************* +* +* OnSnapshotLoad +* +* Function description +* Called upon loading a snapshot. Optional. +* +* Additional information +* This function is used to restore the target state in cases +* where values cannot simply be written to the target. +* Typical use: GPIO clock needs to be enabled, before +* GPIO is configured. +* +********************************************************************** +*/ +//void OnSnapshotLoad (void) { +//} + +/********************************************************************* +* +* OnSnapshotSave +* +* Function description +* Called upon saving a snapshot. Optional. +* +* Additional information +* This function is usually used to save values of the target +* state which can either not be trivially read, +* or need to be restored in a specific way or order. +* Typically use: Memory Mapped Registers, +* such as PLL and GPIO configuration. +* +********************************************************************** +*/ +//void OnSnapshotSave (void) { +//} + +/********************************************************************* +* +* OnError +* +* Function description +* Called when an error ocurred. Optional. +* +********************************************************************** +*/ +//void OnError (void) { +//} + +/********************************************************************* +* +* AfterProjectLoad +* +* Function description +* After Project load routine. Optional. +* +********************************************************************** +*/ +//void AfterProjectLoad (void) { +//} + +/********************************************************************* +* +* _SetupTarget +* +* Function description +* Setup the target. +* Called by AfterTargetReset() and AfterTargetDownload(). +* +* Auto-generated function. May be overridden by Ozone. +* +********************************************************************** +*/ +void _SetupTarget(void) { + // + // this function is intentionally empty because both inital PC and + // initial SP were chosen not to be set + // +} diff --git a/contrib/debug/Release.jdebug b/contrib/debug/Release.jdebug new file mode 100644 index 0000000000..9f1a90b4f0 --- /dev/null +++ b/contrib/debug/Release.jdebug @@ -0,0 +1,334 @@ +/********************************************************************* +* (c) SEGGER Microcontroller GmbH * +* The Embedded Experts * +* www.segger.com * +********************************************************************** + +File : C:/Data/Downloads/Deluge.jdebug +Created : 29 Sep 2023 10:11 +Ozone Version : V3.30b +*/ + +/********************************************************************* +* +* OnProjectLoad +* +* Function description +* Project load routine. Required. +* +********************************************************************** +*/ +void OnProjectLoad (void) { + // + // Dialog-generated settings + // + Project.AddPathSubstitute ("C:/Data/Downloads", "$(ProjectDir)"); + Project.AddPathSubstitute ("c:/data/downloads", "$(ProjectDir)"); + Project.SetTraceSource ("Trace Buffer"); + Project.SetDevice ("R7S721020"); + Project.SetHostIF ("USB", "600000832"); + Project.SetTargetIF ("SWD"); + Project.SetTIFSpeed ("4 MHz"); + Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-A9.svd"); + // + // User settings + // + Edit.Preference (PREF_TIMESTAMP_FORMAT, TIMESTAMP_FORMAT_INST_CNT); + File.Open ("../../build/Release/deluge.elf"); + Edit.SysVar (VAR_TRACE_CORE_CLOCK, 400000000); +} + +/********************************************************************* +* +* OnStartupComplete +* +* Function description +* Called when program execution has reached/passed +* the startup completion point. Optional. +* +********************************************************************** +*/ +//void OnStartupComplete (void) { +//} + +/********************************************************************* +* +* TargetReset +* +* Function description +* Replaces the default target device reset routine. Optional. +* +* Notes +* This example demonstrates the usage when +* debugging an application in RAM on a Cortex-M target device. +* +********************************************************************** +*/ +//void TargetReset (void) { +// +// unsigned int SP; +// unsigned int PC; +// unsigned int VectorTableAddr; +// +// VectorTableAddr = Elf.GetBaseAddr(); +// // +// // Set up initial stack pointer +// // +// if (VectorTableAddr != 0xFFFFFFFF) { +// SP = Target.ReadU32(VectorTableAddr); +// Target.SetReg("SP", SP); +// } +// // +// // Set up entry point PC +// // +// PC = Elf.GetEntryPointPC(); +// +// if (PC != 0xFFFFFFFF) { +// Target.SetReg("PC", PC); +// } else if (VectorTableAddr != 0xFFFFFFFF) { +// PC = Target.ReadU32(VectorTableAddr + 4); +// Target.SetReg("PC", PC); +// } else { +// Util.Error("Project file error: failed to set entry point PC", 1); +// } +//} + +/********************************************************************* +* +* BeforeTargetReset +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetReset (void) { +//} + +/********************************************************************* +* +* AfterTargetReset +* +* Function description +* Event handler routine. Optional. +* The default implementation initializes SP and PC to reset values. +** +********************************************************************** +*/ +void AfterTargetReset (void) { + _SetupTarget(); +} + +/********************************************************************* +* +* DebugStart +* +* Function description +* Replaces the default debug session startup routine. Optional. +* +********************************************************************** +*/ +//void DebugStart (void) { +//} + +/********************************************************************* +* +* TargetConnect +* +* Function description +* Replaces the default target IF connection routine. Optional. +* +********************************************************************** +*/ +//void TargetConnect (void) { +//} + +/********************************************************************* +* +* BeforeTargetConnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetConnect (void) { +//} + +/********************************************************************* +* +* AfterTargetConnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetConnect (void) { +//} + +/********************************************************************* +* +* TargetDownload +* +* Function description +* Replaces the default program download routine. Optional. +* +********************************************************************** +*/ +//void TargetDownload (void) { +//} + +/********************************************************************* +* +* BeforeTargetDownload +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetDownload (void) { +//} + +/********************************************************************* +* +* AfterTargetDownload +* +* Function description +* Event handler routine. Optional. +* The default implementation initializes SP and PC to reset values. +* +********************************************************************** +*/ +void AfterTargetDownload (void) { + _SetupTarget(); +} + +/********************************************************************* +* +* BeforeTargetDisconnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetDisconnect (void) { +//} + +/********************************************************************* +* +* AfterTargetDisconnect +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetDisconnect (void) { +//} + +/********************************************************************* +* +* AfterTargetHalt +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void AfterTargetHalt (void) { +//} + +/********************************************************************* +* +* BeforeTargetResume +* +* Function description +* Event handler routine. Optional. +* +********************************************************************** +*/ +//void BeforeTargetResume (void) { +//} + +/********************************************************************* +* +* OnSnapshotLoad +* +* Function description +* Called upon loading a snapshot. Optional. +* +* Additional information +* This function is used to restore the target state in cases +* where values cannot simply be written to the target. +* Typical use: GPIO clock needs to be enabled, before +* GPIO is configured. +* +********************************************************************** +*/ +//void OnSnapshotLoad (void) { +//} + +/********************************************************************* +* +* OnSnapshotSave +* +* Function description +* Called upon saving a snapshot. Optional. +* +* Additional information +* This function is usually used to save values of the target +* state which can either not be trivially read, +* or need to be restored in a specific way or order. +* Typically use: Memory Mapped Registers, +* such as PLL and GPIO configuration. +* +********************************************************************** +*/ +//void OnSnapshotSave (void) { +//} + +/********************************************************************* +* +* OnError +* +* Function description +* Called when an error ocurred. Optional. +* +********************************************************************** +*/ +//void OnError (void) { +//} + +/********************************************************************* +* +* AfterProjectLoad +* +* Function description +* After Project load routine. Optional. +* +********************************************************************** +*/ +//void AfterProjectLoad (void) { +//} + +/********************************************************************* +* +* _SetupTarget +* +* Function description +* Setup the target. +* Called by AfterTargetReset() and AfterTargetDownload(). +* +* Auto-generated function. May be overridden by Ozone. +* +********************************************************************** +*/ +void _SetupTarget(void) { + // + // this function is intentionally empty because both inital PC and + // initial SP were chosen not to be set + // +} diff --git a/docs/community_features.md b/docs/community_features.md index fc3f941de1..bef43f8d13 100644 --- a/docs/community_features.md +++ b/docs/community_features.md @@ -58,7 +58,7 @@ Here is a list of features that have been added to the firmware as a list, group ### 4.1 - Song View Features #### 4.1.1 - Master Compressor -- ([#630]) In the Song view, select "AFFECT ENTIRE" and "SIDECHAIN" modulation button, and adjust the upper gold knob for a single knob compressor with auto makeup gain. For detailed editing, press the sidechain gold knob. The top LED will become a compression meter. The bottom (reverb) knob will adjust the ratio in this mode, from 1:2 to 1:20. Pressing the bottom knob will toggle between ratio, attack, and release. +- ([#630]) In the Song view, select "AFFECT ENTIRE" and "SIDECHAIN" modulation button, and adjust the upper gold knob for a single knob compressor with auto makeup gain. For detailed editing, press the sidechain gold knob. The top LED will become a compression meter. Clicking the bottom knob will cycle through additional params: ratio (displays actual ratio), attack/release (shown in ms) and sidechain HPF (shown in Hz). The sidechain HPF is useful to remove some bass from the compressor level detection, which sounds like an increase in bass allowed through the compression. #### 4.1.2 - Change Row Colour @@ -107,25 +107,10 @@ Here is a list of features that have been added to the firmware as a list, group ### 4.2 - Clip View - General Features (Instrument and Audio Clips) #### 4.2.1 - Filters - - ([#103]) Adds a new filter in the low-pass slot, a state-variable filter. This filter has significantly less distortion than the ladder filters, think sequential vs. moog. Cutoff and resonance ranges are subject to change with further testing. + - ([#103] and [#336]) Adds 2 new state variable filters to both high and lowpass slots. This filter has significantly less distortion than the ladder filters, think sequential vs. moog. The morph parameter (pad under db/oct) adjusts smoothly from lowpass -> bandpass/notch -> highpass. The knob is inverted in the HPF slot so that at 0 the filter is highpass and at 50 it is lowpassed. + - The morph param is also added to the ladders, in 12/24/drive filters it smoothly increases drive and in the HPF ladder it adds filter FM. This param is modulatable and automatable - - Follow-up PR's: ([#125] and [#212]) Various SVF fixes - -- ([#336]) Morphable and Driveable Parallel Filters - - Add an SVF option to the HPF slot, set for HPF mode by default. This can be modified through the menu, shortcuts, or clicking the lower knob while HPF is selected. - - - Follow-up PR: ([#339]) SVF Notch Filter - - Adds an SVF notch mode (SV_Notch) alongside the SVF Band mode (SV_Band) - - Changes SVF morph in HP slot to go HP-band/notch-LP (HP by default) - - Tweaks default ladder saturation to match original firmware - - Applies ladder gain on input instead of feedback, avoiding interaction with resonance - - Tweaks SVF level to match ladder volumes - - Removes distinction between high and lowpass SVF enums so they can now be used in either slot -adds HP ladder morph to filter FM - - - Adds a 3rd filter paramater called morph, placed in the menu and on the pads under the db/oct on filters. Morph smoothly morphs the SVF through LP-BP-HP, and smoothly increases drive in the ladder filters. This param is modulatable and automatable - - - Adds a setting to switch the filter order or run them in parallel. This setting is menu only and named ROUTE + - Also adds a setting to switch the filter order or run them in parallel. This setting is menu only and named ROUTE #### 4.2.2 - Stereo Chorus - ([#120]) New Stereo Chorus type added to Mod FX. The recommended settings are OFFSET=30, DEPTH=17, and RATE=15. @@ -196,9 +181,10 @@ Synchronization modes accessible through the "LFO SYNC" shortcut. #### 4.3.3 - Quantize & Humanize - ([#129]) - - Press and hold a note in clip view and turn the tempo knob right or left to apply quantize or humanize respectively to that row. - - Press and hold a note and press and turn the tempo knob to apply quantize or humanize to all rows. + - Press and hold an audition pad in clip view and turn the tempo knob right or left to apply quantize or humanize respectively to that row. + - Press and hold an audition pad and press and turn the tempo knob to apply quantize or humanize to all rows. - The amount of quantization/humanization is shown in the display. + - This is destructive (your original note positions are not saved) The implementation of this feature is likely to change in the future - This feature can be turned ON/OFF in the Runtime Settings (Community Features) Menu (accessed by pressing "SHIFT" + "SELECT"). #### 4.3.4 - Fill Mode @@ -301,8 +287,6 @@ In the main menu of the deluge (accessed by pressing "SHIFT" + the "SELECT" knob * Drum Randomizer (DRUM) * When On, the "AUDITION + RANDOM" shortcut is enabled. -* Master Compressor (COMP) - * When On, the Master Compressor is enabled. * Fine Tempo Knob (TEMP) * When On, the Fine Tempo change option is enabled. * Quantize (QUAN) diff --git a/src/definitions_cxx.hpp b/src/definitions_cxx.hpp index d4274480a4..9fca5edb7e 100644 --- a/src/definitions_cxx.hpp +++ b/src/definitions_cxx.hpp @@ -627,9 +627,10 @@ enum class ModFXType { CHORUS, PHASER, CHORUS_STEREO, - GRAIN, + GRAIN, // Look below if you want to add another one }; +// Warning: Currently GRAIN can be disabled and kNumModFXTypes might need to be used - 1 constexpr int32_t kNumModFXTypes = util::to_underlying(ModFXType::GRAIN) + 1; constexpr int32_t SAMPLE_MAX_TRANSPOSE = 24; diff --git a/src/deluge/gui/l10n/english.cpp b/src/deluge/gui/l10n/english.cpp index a1742439be..0fcd6ff63b 100644 --- a/src/deluge/gui/l10n/english.cpp +++ b/src/deluge/gui/l10n/english.cpp @@ -509,6 +509,7 @@ PLACE_SDRAM_DATA Language english{ {STRING_FOR_COMMUNITY_FEATURE_SYNC_SCALING_ACTION, "Sync Scaling Action"}, {STRING_FOR_COMMUNITY_FEATURE_HIGHLIGHT_INCOMING_NOTES, "Highlight Incoming Notes"}, {STRING_FOR_COMMUNITY_FEATURE_NORNS_LAYOUT, "Display Norns Layout"}, + {STRING_FOR_COMMUNITY_FEATURE_GRAIN_FX, "Enable Grain FX"}, {STRING_FOR_TRACK_STILL_HAS_CLIPS_IN_SESSION, "Track still has clips in session"}, {STRING_FOR_DELETE_ALL_TRACKS_CLIPS_FIRST, "Delete all track's clips first"}, diff --git a/src/deluge/gui/l10n/seven_segment.cpp b/src/deluge/gui/l10n/seven_segment.cpp index c16e43e8a5..0c19c83031 100644 --- a/src/deluge/gui/l10n/seven_segment.cpp +++ b/src/deluge/gui/l10n/seven_segment.cpp @@ -348,6 +348,7 @@ PLACE_SDRAM_DATA Language seven_segment{ {STRING_FOR_COMMUNITY_FEATURE_SYNC_SCALING_ACTION, "SCAL"}, {STRING_FOR_COMMUNITY_FEATURE_HIGHLIGHT_INCOMING_NOTES, "HIGH"}, {STRING_FOR_COMMUNITY_FEATURE_NORNS_LAYOUT, "NORN"}, + {STRING_FOR_COMMUNITY_FEATURE_GRAIN_FX, "GRFX"}, {STRING_FOR_TRACK_STILL_HAS_CLIPS_IN_SESSION, "CANT"}, {STRING_FOR_DELETE_ALL_TRACKS_CLIPS_FIRST, "CANT"}, diff --git a/src/deluge/gui/l10n/strings.h b/src/deluge/gui/l10n/strings.h index 16dd9e8f43..4b39208b74 100644 --- a/src/deluge/gui/l10n/strings.h +++ b/src/deluge/gui/l10n/strings.h @@ -412,6 +412,7 @@ enum class String : size_t { STRING_FOR_COMMUNITY_FEATURE_SYNC_SCALING_ACTION, STRING_FOR_COMMUNITY_FEATURE_HIGHLIGHT_INCOMING_NOTES, STRING_FOR_COMMUNITY_FEATURE_NORNS_LAYOUT, + STRING_FOR_COMMUNITY_FEATURE_GRAIN_FX, STRING_FOR_TRACK_STILL_HAS_CLIPS_IN_SESSION, STRING_FOR_DELETE_ALL_TRACKS_CLIPS_FIRST, diff --git a/src/deluge/gui/menu_item/mod_fx/type.h b/src/deluge/gui/menu_item/mod_fx/type.h index ec593afe8d..615ef69e09 100644 --- a/src/deluge/gui/menu_item/mod_fx/type.h +++ b/src/deluge/gui/menu_item/mod_fx/type.h @@ -20,6 +20,7 @@ #include "gui/menu_item/selection.h" #include "gui/ui/sound_editor.h" #include "model/mod_controllable/mod_controllable_audio.h" +#include "model/settings/runtime_feature_settings.h" #include "util/misc.h" namespace deluge::gui::menu_item::mod_fx { @@ -37,6 +38,16 @@ class Type : public Selection { std::vector getOptions() override { using enum l10n::String; + if (runtimeFeatureSettings.get(RuntimeFeatureSettingType::EnableGrainFX) == RuntimeFeatureStateToggle::Off) { + return { + l10n::getView(STRING_FOR_DISABLED), //< + l10n::getView(STRING_FOR_FLANGER), //< + l10n::getView(STRING_FOR_CHORUS), //< + l10n::getView(STRING_FOR_PHASER), //< + l10n::getView(STRING_FOR_STEREO_CHORUS), //< + }; + } + return { l10n::getView(STRING_FOR_DISABLED), //< l10n::getView(STRING_FOR_FLANGER), //< diff --git a/src/deluge/gui/menu_item/runtime_feature/settings.cpp b/src/deluge/gui/menu_item/runtime_feature/settings.cpp index 15a4bc2c65..4d50c10df1 100644 --- a/src/deluge/gui/menu_item/runtime_feature/settings.cpp +++ b/src/deluge/gui/menu_item/runtime_feature/settings.cpp @@ -51,6 +51,7 @@ Setting menuHighlightIncomingNotes(RuntimeFeatureSettingType::HighlightIncomingN Setting menuDisplayNornsLayout(RuntimeFeatureSettingType::DisplayNornsLayout); ShiftIsSticky menuShiftIsSticky{}; Setting menuLightShiftLed(RuntimeFeatureSettingType::LightShiftLed); +Setting menuEnableGrainFX(RuntimeFeatureSettingType::EnableGrainFX); Submenu subMenuAutomation{ l10n::String::STRING_FOR_COMMUNITY_FEATURE_AUTOMATION, @@ -79,7 +80,7 @@ std::arrayfilePointer.sclust) { + Debug::print("FPs don't match: correct is "); + Debug::print(tempfp.sclust); + Debug::print(" but the browser has "); + Debug::println(currentFileItem->filePointer.sclust); +#if ALPHA_OR_BETA_VERSION + display->freezeWithError("B001"); +#endif + return false; + } + return true; +} + void Browser::close() { emptyFileItems(); QwertyUI::close(); @@ -518,6 +547,7 @@ int32_t Browser::readFileItemsFromFolderAndMemory(Song* song, InstrumentType ins } } } + return NO_ERROR; } @@ -934,7 +964,7 @@ void Browser::selectEncoderAction(int8_t offset) { if (thisSlot.slot < 0) { goto nonNumeric; } - + Debug::println("treating as numeric"); thisSlot.subSlot = -1; switch (numberEditPosNow) { case 0: @@ -983,6 +1013,7 @@ void Browser::selectEncoderAction(int8_t offset) { if (thisSlot.slot < 0) { goto nonNumeric; } + Debug::println("treating as numeric"); thisSlot.slot += offset; char searchString[9]; @@ -1012,6 +1043,7 @@ void Browser::selectEncoderAction(int8_t offset) { int32_t error; if (newFileIndex < 0) { + Debug::println("index below 0"); if (numFileItemsDeletedAtStart) { scrollPosVertical = 9999; @@ -1021,12 +1053,15 @@ void Browser::selectEncoderAction(int8_t offset) { NULL, true, Availability::ANY, CATALOG_SEARCH_BOTH); if (error) { gotErrorAfterAllocating: + Debug::println("error while reloading, emptying file items"); emptyFileItems(); return; // TODO - need to close UI or something? } newFileIndex = fileItems.search(enteredText.get()) + offset; + Debug::print("new file Index is "); + Debug::println(newFileIndex); } else if (!shouldWrapFolderContents && display->have7SEG()) { @@ -1057,6 +1092,7 @@ void Browser::selectEncoderAction(int8_t offset) { } else if (newFileIndex >= fileItems.getNumElements()) { + Debug::println("out of file items"); if (numFileItemsDeletedAtEnd) { scrollPosVertical = 0; goto tryReadingItems; diff --git a/src/deluge/gui/ui/browser/browser.h b/src/deluge/gui/ui/browser/browser.h index b8188be386..936d1c2fd2 100644 --- a/src/deluge/gui/ui/browser/browser.h +++ b/src/deluge/gui/ui/browser/browser.h @@ -86,6 +86,7 @@ class Browser : public QwertyUI { int32_t getUnusedSlot(InstrumentType instrumentType, String* newName, char const* thingName); bool opened(); void cullSomeFileItems(); + bool checkFP(); void renderOLED(uint8_t image[][OLED_MAIN_WIDTH_PIXELS]); @@ -142,3 +143,20 @@ class Browser : public QwertyUI { char const* filePrefix; bool shouldInterpretNoteNamesForThisBrowser; }; + +#include "io/debug/print.h" +inline void printInstrumentFileList(const char* where) { + Debug::print("\n"); + Debug::print(where); + Debug::print(" List: \n"); + for (uint32_t idx = 0; idx < Browser::fileItems.getNumElements(); ++idx) { + FileItem* fileItem = (FileItem*)Browser::fileItems.getElementAddress(idx); + Debug::print(" - "); + Debug::print(fileItem->displayName); + Debug::print(" ("); + Debug::print(fileItem->filePointer.sclust); + Debug::print(")\n"); + } + + Debug::print("\n"); +} diff --git a/src/deluge/gui/ui/load/load_instrument_preset_ui.cpp b/src/deluge/gui/ui/load/load_instrument_preset_ui.cpp index 08730200ec..9b1fc0a22e 100644 --- a/src/deluge/gui/ui/load/load_instrument_preset_ui.cpp +++ b/src/deluge/gui/ui/load/load_instrument_preset_ui.cpp @@ -260,7 +260,12 @@ void LoadInstrumentPresetUI::enterKeyPress() { else { if (currentInstrumentLoadError) { - currentInstrumentLoadError = performLoad(); + if (loadingSynthToKitRow) { + currentInstrumentLoadError = performLoadSynthToKit(); + } + else { + currentInstrumentLoadError = performLoad(); + } if (currentInstrumentLoadError) { display->displayError(currentInstrumentLoadError); return; @@ -796,6 +801,7 @@ int32_t LoadInstrumentPresetUI::performLoad(bool doClone) { if (currentFileItem->instrument == instrumentToReplace && !doClone) { return NO_ERROR; // Happens if navigate over a folder's name (Instrument stays the same), } + // then back onto that neighbouring Instrument - you'd incorrectly get a "USED" error without this line. // Work out availabilityRequirement. This can't change as presets are navigated through... I don't think? @@ -854,7 +860,8 @@ int32_t LoadInstrumentPresetUI::performLoad(bool doClone) { } } int32_t error; - + //check if the file pointer matches the current file item + //Browser::checkFP(); error = storageManager.loadInstrumentFromFile(currentSong, instrumentClipToLoadFor, instrumentTypeToLoad, false, &newInstrument, ¤tFileItem->filePointer, &enteredText, ¤tDir); diff --git a/src/deluge/gui/ui/menus.cpp b/src/deluge/gui/ui/menus.cpp index 648695b7a3..b91674622e 100644 --- a/src/deluge/gui/ui/menus.cpp +++ b/src/deluge/gui/ui/menus.cpp @@ -564,10 +564,10 @@ Submenu audioClipModFXMenu{ }; // Delay Menu -UnpatchedParam audioClipDelayRateMenu{STRING_FOR_AMOUNT, STRING_FOR_DELAY_AMOUNT, - ::Param::Unpatched::GlobalEffectable::DELAY_AMOUNT}; -UnpatchedParam audioClipDelayFeedbackMenu{STRING_FOR_RATE, STRING_FOR_DELAY_RATE, - ::Param::Unpatched::GlobalEffectable::DELAY_RATE}; +UnpatchedParam audioClipDelayFeedbackMenu{STRING_FOR_AMOUNT, STRING_FOR_DELAY_AMOUNT, + ::Param::Unpatched::GlobalEffectable::DELAY_AMOUNT}; +UnpatchedParam audioClipDelayRateMenu{STRING_FOR_RATE, STRING_FOR_DELAY_RATE, + ::Param::Unpatched::GlobalEffectable::DELAY_RATE}; Submenu audioClipDelayMenu{ STRING_FOR_DELAY, diff --git a/src/deluge/gui/views/automation_instrument_clip_view.cpp b/src/deluge/gui/views/automation_instrument_clip_view.cpp index 5a2c84bf97..b08a709dca 100644 --- a/src/deluge/gui/views/automation_instrument_clip_view.cpp +++ b/src/deluge/gui/views/automation_instrument_clip_view.cpp @@ -816,9 +816,15 @@ void AutomationInstrumentClipView::renderDisplay(int32_t knobPosLeft, int32_t kn InstrumentClip* clip = getCurrentClip(); Instrument* instrument = (Instrument*)clip->output; - knobPosLeft = view.calculateKnobPosForDisplay(clip->lastSelectedParamKind, clip->lastSelectedParamID, knobPosLeft); - knobPosRight = - view.calculateKnobPosForDisplay(clip->lastSelectedParamKind, clip->lastSelectedParamID, knobPosRight); + //if you're not in a MIDI instrument clip, convert the knobPos to the same range as the menu (0-50) + if (instrument->type != InstrumentType::MIDI_OUT) { + if (knobPosLeft != kNoSelection) { + knobPosLeft = view.calculateKnobPosForDisplay(clip->lastSelectedParamKind, clip->lastSelectedParamID, knobPosLeft); + } + if (knobPosRight != kNoSelection) { + knobPosRight = view.calculateKnobPosForDisplay(clip->lastSelectedParamKind, clip->lastSelectedParamID, knobPosRight); + } + } //OLED Display if (display->haveOLED()) { @@ -946,7 +952,8 @@ void AutomationInstrumentClipView::renderDisplay7SEG(InstrumentClip* clip, Instr lastPadSelectedKnobPos = knobPosLeft; } else if (lastPadSelectedKnobPos != kNoSelection) { - knobPosLeft = lastPadSelectedKnobPos; + knobPosLeft = view.calculateKnobPosForDisplay(clip->lastSelectedParamKind, clip->lastSelectedParamID, + lastPadSelectedKnobPos); } } @@ -957,10 +964,10 @@ void AutomationInstrumentClipView::renderDisplay7SEG(InstrumentClip* clip, Instr intToString(knobPosLeft, buffer); if (isUIModeActive(UI_MODE_NOTES_PRESSED)) { - display->setText(buffer, false, 255, false); + display->setText(buffer, true, 255, false); } else if (modEncoderAction || padSelectionOn) { - display->displayPopup(buffer); + display->displayPopup(buffer, 3, true); } } //display parameter name @@ -1011,7 +1018,7 @@ void AutomationInstrumentClipView::getParameterName(InstrumentClip* clip, Instru //adjust the LED meters and update the display -/*updated function for displaying automation when playback is enabled (called from ui_timer_manager). +/*updated function for displaying automation when playback is enabled (called from ui_timer_manager). Also used internally in the automation instrument clip view for updating the display and led indicators.*/ void AutomationInstrumentClipView::displayAutomation(bool padSelected, bool updateDisplay) { diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index ed9e9aeab5..0ba541e916 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -128,6 +128,7 @@ bool SessionView::opened() { } void SessionView::focusRegained() { + horizontalEncoderPressed = false; selectLayout(0); // Make sure we get a valid layout from the loaded file bool doingRender = (currentUIMode != UI_MODE_ANIMATION_FADE); @@ -360,6 +361,28 @@ ActionResult SessionView::buttonAction(deluge::hid::Button b, bool on, bool inCa return ActionResult::NOT_DEALT_WITH; // Make the MatrixDriver do its normal thing with it too } + // Overwrite to allow not showing zoom level in grid + else if (b == X_ENC) { + horizontalEncoderPressed = on; + if (on) { + // Show current zoom level + if (isNoUIModeActive() && (currentSong->sessionLayout != SessionLayoutType::SessionLayoutTypeGrid)) { + displayZoomLevel(); + } + + enterUIMode(UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON); + } + + else { + if (isUIModeActive(UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON)) { + if (currentSong->sessionLayout != SessionLayoutType::SessionLayoutTypeGrid) { + display->cancelPopup(); + } + exitUIMode(UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON); + } + } + } + // If save / delete button pressed, delete the Clip! else if (b == SAVE && (currentUIMode == UI_MODE_CLIP_PRESSED_IN_SONG_VIEW || gridFirstPadActive())) { if (on) { @@ -3525,7 +3548,7 @@ ActionResult SessionView::gridHandlePadsLaunchWithSelection(int32_t x, int32_t y void SessionView::gridHandlePadsLaunchToggleArming(Clip* clip, bool immediate) { if (immediate) { - if (currentUIMode == UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON) { + if (horizontalEncoderPressed) { session.soloClipAction(clip, kInternalButtonPressLatency); } else { @@ -3533,7 +3556,10 @@ void SessionView::gridHandlePadsLaunchToggleArming(Clip* clip, bool immediate) { } } else { - if (currentUIMode == UI_MODE_VIEWING_RECORD_ARMING) { + if (horizontalEncoderPressed) { + session.soloClipAction(clip, kInternalButtonPressLatency); + } + else if (currentUIMode == UI_MODE_VIEWING_RECORD_ARMING) { // Here I removed the overdubbing settings clip->armedForRecording = !clip->armedForRecording; PadLEDs::reassessGreyout(true); @@ -3546,18 +3572,10 @@ void SessionView::gridHandlePadsLaunchToggleArming(Clip* clip, bool immediate) { || currentUIMode == UI_MODE_STUTTERING)) { gridToggleClipPlay(clip, false); } - else if (currentUIMode == UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON) { - session.soloClipAction(clip, kInternalButtonPressLatency); - // Make sure we can mute additional pads after this and don't loose UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON - } } } ActionResult SessionView::gridHandleScroll(int32_t offsetX, int32_t offsetY) { - if (isUIModeActive(UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON)) { - display->cancelPopup(); - } - if (currentUIMode == UI_MODE_CLIP_PRESSED_IN_SONG_VIEW && offsetY != 0) { auto track = gridTrackFromX(gridFirstPressedX, gridTrackCount()); if (track != nullptr) { diff --git a/src/deluge/gui/views/session_view.h b/src/deluge/gui/views/session_view.h index ce0b0b48b0..f967621a0f 100644 --- a/src/deluge/gui/views/session_view.h +++ b/src/deluge/gui/views/session_view.h @@ -130,7 +130,7 @@ class SessionView final : public ClipNavigationTimelineView { bool sessionButtonActive = false; bool sessionButtonUsed = false; - + bool horizontalEncoderPressed = false; // Members for grid layout private: bool gridRenderSidebar(uint32_t whichRows, uint8_t image[][kDisplayWidth + kSideBarWidth][3], diff --git a/src/deluge/gui/views/view.cpp b/src/deluge/gui/views/view.cpp index 9fc23280d2..422b7b6574 100644 --- a/src/deluge/gui/views/view.cpp +++ b/src/deluge/gui/views/view.cpp @@ -940,6 +940,10 @@ void View::displayModEncoderValuePopup(Param::Kind kind, int32_t paramID, int32_ popupMsg.append(name); popupMsg.append(": "); } + else { + int valueForDisplay = calculateKnobPosForDisplay(kind, paramID, newKnobPos + kKnobPosOffset); + popupMsg.appendInt(valueForDisplay); + } } //if turning stutter mod encoder and stutter quantize is enabled diff --git a/src/deluge/model/clip/instrument_clip.cpp b/src/deluge/model/clip/instrument_clip.cpp index 3cf5988c3a..3a0fa5c297 100644 --- a/src/deluge/model/clip/instrument_clip.cpp +++ b/src/deluge/model/clip/instrument_clip.cpp @@ -2688,7 +2688,7 @@ int32_t InstrumentClip::readFromFile(Song* song) { } } - // These next 3 - only created by alpha testers for a few weeks. Could eventually remove. + // These are the expression params for MPE else if (!strcmp(tagName, "pitchBend")) { temp = 0; doReadExpressionParam: @@ -2900,8 +2900,11 @@ int32_t InstrumentClip::readMIDIParamsFromFile(int32_t readAutomationUpToPos) { paramId = stringToInt(contents); if (paramId < kNumRealCCNumbers) { if (paramId == 74) { - paramId = 1; - goto expressionParam; + if (storageManager.firmwareVersionOfFileBeingRead + < FirmwareVersion::FIRMWARE_3P2P0_ALPHA) { + paramId = 1; + goto expressionParam; + } } MIDIParam* midiParam = paramManager.getMIDIParamCollection()->params.getOrCreateParamFromCC(paramId, 0); diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index f6ca80701b..b4a62208ee 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -122,7 +122,11 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on, else if (modKnobMode == 5) { if (whichModEncoder == 1) { if (on) { - modFXType = static_cast((util::to_underlying(modFXType) + 1) % kNumModFXTypes); + auto modTypeCount = (runtimeFeatureSettings.get(RuntimeFeatureSettingType::EnableGrainFX) + == RuntimeFeatureStateToggle::Off) + ? (kNumModFXTypes - 1) + : kNumModFXTypes; + modFXType = static_cast((util::to_underlying(modFXType) + 1) % modTypeCount); if (modFXType == ModFXType::NONE) { modFXType = static_cast(1); } diff --git a/src/deluge/model/settings/runtime_feature_settings.cpp b/src/deluge/model/settings/runtime_feature_settings.cpp index cb54d983ca..04738e1b9e 100644 --- a/src/deluge/model/settings/runtime_feature_settings.cpp +++ b/src/deluge/model/settings/runtime_feature_settings.cpp @@ -155,6 +155,11 @@ void RuntimeFeatureSettings::init() { // LightShiftLed SetupOnOffSetting(settings[RuntimeFeatureSettingType::LightShiftLed], "Light Shift", "lightShift", RuntimeFeatureStateToggle::Off); + + // EnableGrainFX + SetupOnOffSetting(settings[RuntimeFeatureSettingType::EnableGrainFX], + deluge::l10n::getView(STRING_FOR_COMMUNITY_FEATURE_GRAIN_FX), "enableGrainFX", + RuntimeFeatureStateToggle::Off); } void RuntimeFeatureSettings::readSettingsFromFile() { diff --git a/src/deluge/model/settings/runtime_feature_settings.h b/src/deluge/model/settings/runtime_feature_settings.h index 8d00980584..12f67a4976 100644 --- a/src/deluge/model/settings/runtime_feature_settings.h +++ b/src/deluge/model/settings/runtime_feature_settings.h @@ -57,6 +57,7 @@ enum RuntimeFeatureSettingType : uint32_t { DisplayNornsLayout, ShiftIsSticky, LightShiftLed, + EnableGrainFX, MaxElement // Keep as boundary }; diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 0028323006..775a27a4d2 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -5390,11 +5390,13 @@ int32_t Song::addInstrumentsToFileItems(InstrumentType instrumentType) { } FileItem* thisItem = loadInstrumentPresetUI.getNewFileItem(); + if (!thisItem) { return ERROR_INSUFFICIENT_RAM; } int32_t error = thisItem->setupWithInstrument(thisInstrument, doingHibernatingOnes); + if (error) { return error; } diff --git a/src/deluge/storage/file_item.cpp b/src/deluge/storage/file_item.cpp index be04fa6edf..522366cccf 100644 --- a/src/deluge/storage/file_item.cpp +++ b/src/deluge/storage/file_item.cpp @@ -16,10 +16,12 @@ */ #include "storage/file_item.h" #include "hid/display/display.h" +#include "io/debug/print.h" #include "model/instrument/instrument.h" #include FileItem::FileItem() { + filePointer = {0}; instrument = NULL; filenameIncludesExtension = true; instrumentAlreadyInSong = false; @@ -36,6 +38,15 @@ int32_t FileItem::setupWithInstrument(Instrument* newInstrument, bool hibernatin isFolder = false; instrumentAlreadyInSong = !hibernating; displayName = filename.get(); + String tempFilePath; + tempFilePath.set(newInstrument->dirPath.get()); + tempFilePath.concatenate("/"); + tempFilePath.concatenate(filename.get()); + bool fileExists = storageManager.fileExists(tempFilePath.get(), &filePointer); + if (!fileExists) { + Debug::print("couldn't get filepath for file"); + Debug::println(filename.get()); + } return NO_ERROR; } diff --git a/src/deluge/storage/storage_manager.cpp b/src/deluge/storage/storage_manager.cpp index 7fe19b8e29..77d7480295 100644 --- a/src/deluge/storage/storage_manager.cpp +++ b/src/deluge/storage/storage_manager.cpp @@ -1356,7 +1356,9 @@ void StorageManager::openFilePointer(FilePointer* fp) { int32_t StorageManager::openInstrumentFile(InstrumentType instrumentType, FilePointer* filePointer) { AudioEngine::logAction("openInstrumentFile"); - + if (!filePointer->sclust) { + return ERROR_FILE_NOT_FOUND; + } char const* firstTagName; char const* altTagName = ""; @@ -1379,9 +1381,16 @@ int32_t StorageManager::loadInstrumentFromFile(Song* song, InstrumentClip* clip, FilePointer* filePointer, String* name, String* dirPath) { AudioEngine::logAction("loadInstrumentFromFile"); + Debug::print("opening instrument file - "); + Debug::print(dirPath->get()); + Debug::print(name->get()); + Debug::print(" from FP "); + Debug::println((int32_t)filePointer->sclust); int32_t error = openInstrumentFile(instrumentType, filePointer); if (error) { + Debug::print("opening instrument file failed - "); + Debug::println(name->get()); return error; } @@ -1390,6 +1399,8 @@ int32_t StorageManager::loadInstrumentFromFile(Song* song, InstrumentClip* clip, if (!newInstrument) { closeFile(); + Debug::print("Allocating instrument file failed - "); + Debug::println(name->get()); return ERROR_INSUFFICIENT_RAM; } @@ -1399,12 +1410,15 @@ int32_t StorageManager::loadInstrumentFromFile(Song* song, InstrumentClip* clip, // If that somehow didn't work... if (error || !fileSuccess) { - + Debug::print("reading instrument file failed - "); + Debug::println(name->get()); if (!fileSuccess) { error = ERROR_SD_CARD; } deleteInstrumentAndGetOut: + Debug::print("abandoning load - "); + Debug::println(name->get()); newInstrument->deleteBackedUpParamManagers(song); void* toDealloc = static_cast(newInstrument); newInstrument->~Instrument(); @@ -1432,6 +1446,8 @@ int32_t StorageManager::loadInstrumentFromFile(Song* song, InstrumentClip* clip, } else { paramManagersMissing: + Debug::print("creating param manager failed - "); + Debug::println(name->get()); error = ERROR_FILE_CORRUPTED; goto deleteInstrumentAndGetOut; }