diff --git a/.github/workflows/beta-build.yml b/.github/workflows/beta-build.yml index e060944ce8..c847dbcdb9 100644 --- a/.github/workflows/beta-build.yml +++ b/.github/workflows/beta-build.yml @@ -5,7 +5,7 @@ on: push: branches: - 'release/1.0' - pull_request: + pull_request_target: types: - closed branches: diff --git a/.vscode/launch.json b/.vscode/launch.json index d0f9cad265..e2da8dfd0e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,13 +17,36 @@ "request": "launch", "cwd": "${workspaceRoot}", "executable": "${workspaceRoot}/build/Debug/deluge.elf", + "windows": { + "serverpath": "C:\\Program Files\\SEGGER\\JLink\\JLinkGDBServerCL.exe", + }, "servertype": "jlink", "device": "R7S721020", "interface": "swd", - "runToEntryPoint": "main", + //"runToEntryPoint": "main", "svdFile": "${workspaceRoot}/contrib/rza1.svd", + "overrideLaunchCommands": [ + "monitor reset", + "load" + ], + "overrideResetCommands": [ + "monitor reset", + "load" + ], + "overrideRestartCommands": [ + "monitor reset", + "load" + ], "rttConfig": { "enabled": true, + "address": "auto", + "decoders": [ + { + "port": 0, + "timestamp": true, + "type": "console" + } + ] }, }, { @@ -54,8 +77,11 @@ "MIMode": "gdb", "miDebuggerPath": "arm-none-eabi-gdb", "windows": { - "miDebuggerPath": "${workspaceRoot}/toolchain/win32-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb.exe" + "miDebuggerPath": "${workspaceRoot}/toolchain/win32-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb.exe", + "debugServerPath": "C:/Program Files/SEGGER/JLink/JLinkGDBServerCL.exe", }, + "debugServerArgs": "-select USB -device R7S721020 -endian little -if SWD -speed auto -noir -LocalhostOnly -nologtofile -port 3333 -SWOPort 2332 -TelnetPort 2333", + "serverStarted": "Connected to target", "linux": { "miDebuggerPath": "${workspaceRoot}/toolchain/linux-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb" }, @@ -75,8 +101,11 @@ "MIMode": "gdb", "miDebuggerPath": "arm-none-eabi-gdb", "windows": { - "miDebuggerPath": "${workspaceRoot}/toolchain/win32-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb.exe" + "miDebuggerPath": "${workspaceRoot}/toolchain/win32-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb.exe", + "debugServerPath": "C:/Program Files/SEGGER/JLink/JLinkGDBServerCL.exe", }, + "debugServerArgs": "-select USB -device R7S721020 -endian little -if SWD -speed auto -noir -LocalhostOnly -nologtofile -port 3333 -SWOPort 2332 -TelnetPort 2333", + "serverStarted": "Connected to target", "linux": { "miDebuggerPath": "${workspaceRoot}/toolchain/linux-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb" }, @@ -115,8 +144,11 @@ "MIMode": "gdb", "miDebuggerPath": "arm-none-eabi-gdb", "windows": { - "miDebuggerPath": "${workspaceRoot}/toolchain/win32-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb.exe" + "miDebuggerPath": "${workspaceRoot}/toolchain/win32-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb.exe", + "debugServerPath": "C:/Program Files/SEGGER/JLink/JLinkGDBServerCL.exe", }, + "debugServerArgs": "-select USB -device R7S721020 -endian little -if SWD -speed auto -noir -LocalhostOnly -nologtofile -port 3333 -SWOPort 2332 -TelnetPort 2333", + "serverStarted": "Connected to target", "linux": { "miDebuggerPath": "${workspaceRoot}/toolchain/linux-x86_64/arm-none-eabi-gcc/bin/arm-none-eabi-gdb" }, @@ -151,7 +183,7 @@ "type": "lldb", "request": "launch", "targetCreateCommands": [ - "target create ${workspaceFolder}/build/debug/deluge7SEG.elf" + "target create ${workspaceFolder}/build/Debug/deluge.elf" ], "processCreateCommands": [ "gdb-remote localhost:3333" diff --git a/.vscode/settings.json b/.vscode/settings.json index a9951250ef..5fde7b3f58 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,4 +15,5 @@ "SDRAM", "Synthstrom" ], + "cortex-debug.armToolchainPath.windows": "${workspaceRoot}/toolchain/win32-x86_64/arm-none-eabi-gcc/bin", } diff --git a/CMakeLists.txt b/CMakeLists.txt index c6ad0b4c6e..44677079fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ execute_process( string(TIMESTAMP DATE_TODAY "%Y.%m.%d") # Build our version string +set(BUILD_COMMIT_SHORT "${GIT_COMMIT_SHORT}") # Used in firmware set(BUILD_VERSION_STRING "${PROJECT_VERSION}${SEMVER_PRERELEASE_ID}-${GIT_COMMIT_SHORT}") # Used in firmware set(BUILD_VERSION_SUFFIX "-v${PROJECT_VERSION}${SEMVER_PRERELEASE_ID}+${DATE_TODAY}-${GIT_COMMIT_SHORT}") # Used for filename @@ -125,8 +126,8 @@ add_compile_options( -fdiagnostics-parseable-fixits -fsigned-char - # Debug symbols - $<$:-ggdb3> # Include + # Debug symbols, also for release so we get a full ELF + $<$:-ggdb3> # Include # Optimization level $<$:-Og> @@ -215,7 +216,8 @@ target_link_options(deluge PUBLIC LINKER:--gc-sections LINKER:--entry=start # Set the entrypoint to 'start' (see RZA1/compiler/asm/start.S) - $<$:LINKER:--strip-all> # Strip + # Enabled to generate a full ELF, objcopy will do the stripping + # $<$:LINKER:--strip-all> # Strip -nostartfiles # Don't emit startfiles diff --git a/docs/community_features.md b/docs/community_features.md index 9892d55a12..d4b0365f82 100644 --- a/docs/community_features.md +++ b/docs/community_features.md @@ -38,6 +38,16 @@ Here is a list of general improvements that have been made, ordered from newest #### 3.7 - Mod Wheel - ([#512]) Incoming mod wheel on non-MPE synths now maps to y axis +#### 3.8 - Visual Feedback on Value Changes with Mod Encoders and Increased Resolution for Value's in Menu's +- ([#636]) Changing parameter values with Mod (Gold) Encoders now displays a pop-up with the current value of the Parameter. The Menu's for Parameters and Patch Cables have also been adjusted to show the same value range as displayed with the Mod Encoders. + - This allows for better fine-tuning of values. + - The value range displayed is 0-50 for non-MIDI parameters and 0-127 for MIDI parameters. + - Note: In the Menu, if you wish to scroll through the parameter value range faster at an accelerated rate of +/- 5, hold Shift while turning the Select Encoder. + +#### 3.9 - Adjust Metronome Volume +- ([#683]) The Metronome's volume now respects the song's volume and will increase and decrease in volume together with the Gold Volume Encoder. + - In addition, a Default menu was created titled "Metronome" which enables you to set a value between 22 and 27 to further adjust the volume of the Metronome. 22 being the lowest metronome volume that can be heard when the Song's volume is at its maximum and 27 being the loudest metronome volume. + ## 4. New Features Added Here is a list of features that have been added to the firmware as a list, grouped by category: @@ -58,7 +68,6 @@ Here is a list of features that have been added to the firmware as a list, group - Default (DEFA) - the default Deluge clip type. - Fill (FILL) - Fill clip. It appears orange/cyan on the status pads, and when triggered it will schedule itself to start at such a time that it _finishes_ at the start of the next loop. If the fill clip is longer than the remaining time, it is triggered immediately at a point midway through. The loop length is set by the longest playing clip, or by the total length of a section times the repeat count set for that section. **Limitation**: a fill clip is still subject to the one clip per instrument behavior of the Deluge. Fill clips can steal an output from another fill, but they cannot steal from a non-fill. This can lead to some fills never starting since a default type clip has the needed instrument. This can be worked around by cloning the instrument to an independent copy. - #### 4.1.4 - Catch Notes - ([#221]) The normal behavior of the Deluge is to try to keep up with 'in progress' notes when instant switching between clips by playing them late. However this leads to glitches with drum clips and other percussive sounds. Changing this setting to OFF will prevent this behavior and *not* try to keep up with those notes, leading to smoother instant switching between clips. @@ -74,7 +83,12 @@ Here is a list of features that have been added to the firmware as a list, group - Compared to rows layout overdub recording and copying clips to arranger is currently not supported - Every track (column) has a random generated color that can be changed in edit mode (see below) - Launched clips are full color, unlaunched dimmed and during soloing all non soloed clips are greyed out - - A new menu to select the default Layout has been added in Shift+Selection Encoder -> Defaults -> UI -> Song -> Layout + - New default settings that can be reached with Shift+Selection Encoder -> Defaults -> UI -> Song + - Layout: Select the default layout for all new songs + - Grid + - Default active mode: "Selection" allows changing the mode as described below, all other settings will always make mode snap back to the configured one (default Selection) + - Select in green mode: Enabling this will make allow holding clips in green (launch) mode to change their parameters like in blue mode, tradeoff is arming is executed on finger up (default on) + - Empty pad unarm: Enabling will make pressing empty pads in a track unarm all playing tracks in that track (default off) - There are different interaction modes that change how the grid behaves - The mode can be changed by clicking on one of the colored pads in the Audition/Section column on the right - To permanently switch the mode click on a pad and release, to temporarily switch hold the mode pad and use the grid, the mode will snap back to the current permanent one @@ -197,6 +211,11 @@ Synchronization modes accessible through the "LFO SYNC" shortcut. - Follow-up PR's: - ([#347]) Added new automatable parameters - ([#360]) Fixed interpolation bugs, added fine tuning for long presses, and added pad selection mode + - ([#636]) Updated Parameter Values displayed in Automation View to match Parameter Value Ranges displayed in the Menu's. E.g. instead of 0 - 128, it now displays 0 - 50 (except for Pan which now displays -25 to +25 and MIDI instrument clips which now display 0 - 127). + - ([#681]) Added new automation community feature menu to re-instate audition pad shortcuts in the Automation Instrument Clip View. + - Currently in the Instrument Clip View if you hold down an audition pad and press a shortcut pad on the grid, it will open the menu corresponding to that shortcut pad. + - By default in the Automation Instrument Clip View that same behaviour of holding an audition pad and pressing a shortcut pad is disabled in favour of you being able to hold down an audition pad and adjust the automation lane values so that you can audible hear the changes to the sound while adjusting automation settings. + - Through the community features menu, you can disable this change and re-instate the audition pad shortcuts by setting the community feature to "Off." #### 4.3.6 - Set Probability By Row @@ -307,6 +326,12 @@ In the main menu of the deluge (accessed by pressing "SHIFT" + the "SELECT" knob * Shift Note (SHIF) * When On, shifting notes horizontally in the regular Instrument Clip View will shift the Notes and MPE, but not the Automation. * When On, to shift Non-MPE Automation horizontally you will need to enter the Automation Instrument Clip View. + * Disable Audition Pad Shortcuts (SCUT) + * When On, audition pad shortcuts are disabled. Holding an audition pad and pressing a shortcut pad will not activate the shortcut and will not change the selected parameter. + * When On, to change the selected parameter you will need to either: + 1) use the select encoder; + 2) use the shift + shortcut pad combo; or + 3) go back to the automation overview; * Allow Insecure Develop Sysex Messages (SYX) * When On, the ability to load firmware over USB is enabled. * Sync Scaling Action (SCAL) @@ -352,7 +377,6 @@ This list includes all preprocessor switches that can alter firmware behaviour a [#122]: https://github.com/SynthstromAudible/DelugeFirmware/pull/122 [#125]: https://github.com/SynthstromAudible/DelugeFirmware/pull/125 [#129]: https://github.com/SynthstromAudible/DelugeFirmware/pull/129 -[#630]: https://github.com/SynthstromAudible/DelugeFirmware/pull/630 [#138]: https://github.com/SynthstromAudible/DelugeFirmware/pull/138 [#141]: https://github.com/SynthstromAudible/DelugeFirmware/pull/141 [#157]: https://github.com/SynthstromAudible/DelugeFirmware/pull/157 @@ -390,4 +414,8 @@ This list includes all preprocessor switches that can alter firmware behaviour a [#368]: https://github.com/SynthstromAudible/DelugeFirmware/pull/368 [#395]: https://github.com/SynthstromAudible/DelugeFirmware/pull/395 [#512]: https://github.com/SynthstromAudible/DelugeFirmware/pull/512 +[#630]: https://github.com/SynthstromAudible/DelugeFirmware/pull/630 +[#636]: https://github.com/SynthstromAudible/DelugeFirmware/pull/636 +[#681]: https://github.com/SynthstromAudible/DelugeFirmware/pull/681 +[#683]: https://github.com/SynthstromAudible/DelugeFirmware/pull/683 [Automation View Documentation]: https://github.com/SynthstromAudible/DelugeFirmware/blob/release/1.0/docs/features/automation_view.md diff --git a/docs/features/automation_view.md b/docs/features/automation_view.md index 1b7e3ae989..343fa85add 100644 --- a/docs/features/automation_view.md +++ b/docs/features/automation_view.md @@ -146,7 +146,9 @@ The Automation Editor **will:** - enable you to quickly change parameters in focus for editing by turning select or using shift + shortcut pad - enable you to view the current parameter value setting for the parameters that are currently automatable. - illuminate each pad row according to the current value within the range of 0-128. E.g. bottom pad = 0-16, then 17-32, 33-48, 49-64, 65-80, 81-96, 97-112, 113-128) +> **Update** The values displayed in automation view have been updated to display the same value range displayed in the menu's for consistency across the Deluge UI. So instead of displaying 0 - 128, it now displays 0 - 50. Calculations in automation view are still being done based on the 0 - 128 range, but the display converts it to the 0 - 50 range. - edit new or existing parameter automations on a per step basis, at any zoom level across the entire timeline. Each row in a step column corresponds to a range of values in the parameter value range (0-128) (see above). If you press the bottom row, the value will be set to 0. if you press the top row, the value will be set to 128. Pressing the rows in between increments/decrements the value by 18 (e.g. 0, 18, 36, 54, 72, 90, 108, 128). +> **Update** The values displayed in automation view have been updated to display the same value range displayed in the menu's for consistency across the Deluge UI. So instead of displaying 0 - 128, it now displays 0 - 50. Calculations in automation view are still being done based on the 0 - 128 range, but the display converts it to the 0 - 50 range. ![image](https://github.com/seangoodvibes/DelugeFirmware/assets/138174805/8cc7befa-9071-4bd3-ac3c-15049f69b250) @@ -317,6 +319,16 @@ In the Automation Instrument Clip View, functionality is provided to shift autom > **Note:** MPE recorded will still be shifted as the scope of this PR does not cover editing MPE. +### Disable Audition Pad Shortcuts + +Currently in the Instrument Clip View if you hold down an audition pad and press a shortcut pad on the grid, it will open the menu corresponding to that shortcut pad. + +By default in the Automation Instrument Clip View that same behaviour of holding an audition pad and pressing a shortcut pad is disabled in favour of you being able to hold down an audition pad and adjust the automation lane values so that you can audible hear the changes to the sound while adjusting automation settings. + +Through the community features menu, you can disable this change and re-instate the audition pad shortcuts by setting the community feature to "Off." + +> **Note:** in automation view, shortcuts do not open the menu. They change the selected parameter for automation lane editing. + # Fun things to try with the new Automation Instrument Clip View ## Two Hand Automation Drumming diff --git a/linker_script_rz_a1l.ld b/linker_script_rz_a1l.ld index b74d1285dd..8ab0d876e5 100644 --- a/linker_script_rz_a1l.ld +++ b/linker_script_rz_a1l.ld @@ -150,6 +150,8 @@ SECTIONS /* ALIGN(0x20) is only necessary for v0 bootloaders */ .reset : ALIGN(0x20) /* 0x10 isn't enough. Not sure why any of this is necessary though. */ { + PROVIDE(program_code_start = .); + execute = .; *start.S.obj (.text) *start.S.obj (.rodata) @@ -180,6 +182,8 @@ SECTIONS _etext = .; address_end_reset = .; + + PROVIDE(program_code_end = .); } > RAM012L .rodata : diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f89734f403..0fa27c4a70 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_path(SET SHARED_INCLUDE ${CMAKE_CURRENT_LIST_DIR}) -target_sources(deluge PUBLIC main.c resetprg.c c_lib_alternatives.S) +target_sources(deluge PUBLIC main.c resetprg.c fault_handler.c c_lib_alternatives.S) add_subdirectory(deluge) add_subdirectory(RZA1) diff --git a/src/RTT/SEGGER_RTT.c b/src/RTT/SEGGER_RTT.c index 8c19ab1bb3..9f2b987132 100644 --- a/src/RTT/SEGGER_RTT.c +++ b/src/RTT/SEGGER_RTT.c @@ -248,13 +248,13 @@ static unsigned char _aTerminalId[16] = {'0', '1', '2', '3', '4', '5', '6', '7', // // RTT Control Block and allocate buffers for channel 0 // -SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT_REAL)); +SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBufferReal[BUFFER_SIZE_UP])); SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBufferReal[BUFFER_SIZE_DOWN])); // Stuff ingeniously messed with by Rohan to get around cache, which would stop RTT from working -#define _SEGGER_RTT (*(SEGGER_RTT_CB*)((char*)&_SEGGER_RTT_REAL + UNCACHED_MIRROR_OFFSET)) +#define _SEGGER_RTT_UNCACHED (*(SEGGER_RTT_CB*)((char*)&_SEGGER_RTT + UNCACHED_MIRROR_OFFSET)) #define _acUpBuffer ((char*)_acUpBufferReal + UNCACHED_MIRROR_OFFSET) #define _acDownBuffer ((char*)_acDownBufferReal + UNCACHED_MIRROR_OFFSET) @@ -278,7 +278,7 @@ static unsigned char _ActiveTerminal; */ #define INIT() \ do { \ - if (_SEGGER_RTT.acID[0] == '\0') { \ + if (_SEGGER_RTT_UNCACHED.acID[0] == '\0') { \ _DoInit(); \ } \ } while (0) @@ -287,7 +287,7 @@ static void _DoInit(void) { // // Initialize control block // - p = &_SEGGER_RTT; + p = &_SEGGER_RTT_UNCACHED; p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; // @@ -314,7 +314,7 @@ static void _DoInit(void) { // in initializer memory (usually flash) by J-Link // // GCC gets deeply confused by the UNCACHED_MIRROR_OFFSET trickery - // happening inside _SEGGER_RTT. It's not easy to explain what we're doing + // happening inside _SEGGER_RTT_UNCACHED. It's not easy to explain what we're doing // here either, so simply silence the warning for now. #pragma GCC push #pragma GCC diagnostic ignored "-Wstringop-overflow" @@ -556,7 +556,7 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsign #endif // INIT(); - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; pBuffer = (unsigned char*)pData; RdOff = pRing->RdOff; WrOff = pRing->WrOff; @@ -650,7 +650,7 @@ unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned Buffe #endif // INIT(); - pRing = &_SEGGER_RTT.aDown[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aDown[BufferIndex]; pBuffer = (unsigned char*)pData; RdOff = pRing->RdOff; WrOff = pRing->WrOff; @@ -820,7 +820,7 @@ void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuff // // Get "to-host" ring buffer and copy some elements into local variables. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; // // Check if we will overwrite data and need to adjust the RdOff. // @@ -929,7 +929,7 @@ unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, u // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough // pData = (const char*)pBuffer; - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; RdOff = pRing->RdOff; WrOff = pRing->WrOff; if (RdOff <= WrOff) { // Case 1), 2) or 3) @@ -1008,7 +1008,7 @@ unsigned SEGGER_RTT_WriteDownBufferNoLock(unsigned BufferIndex, const void* pBuf // Get "to-target" ring buffer. // It is save to cast that to a "to-host" buffer. Up and Down buffer differ in volatility of offsets that might be modified by J-Link. // - pRing = (SEGGER_RTT_BUFFER_UP*)&_SEGGER_RTT.aDown[BufferIndex]; + pRing = (SEGGER_RTT_BUFFER_UP*)&_SEGGER_RTT_UNCACHED.aDown[BufferIndex]; // // How we output depends upon the mode... // @@ -1084,7 +1084,7 @@ unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsig // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; // // How we output depends upon the mode... // @@ -1262,7 +1262,7 @@ unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c) { // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; // // Get write position and handle wrap-around if necessary // @@ -1315,7 +1315,7 @@ unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) { // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; // // Get write position and handle wrap-around if necessary // @@ -1372,7 +1372,7 @@ unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) { // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; // // Get write position and handle wrap-around if necessary // @@ -1479,8 +1479,8 @@ int SEGGER_RTT_HasKey(void) { int r; INIT(); - RdOff = _SEGGER_RTT.aDown[0].RdOff; - if (RdOff != _SEGGER_RTT.aDown[0].WrOff) { + RdOff = _SEGGER_RTT_UNCACHED.aDown[0].RdOff; + if (RdOff != _SEGGER_RTT_UNCACHED.aDown[0].WrOff) { r = 1; } else { @@ -1505,7 +1505,7 @@ unsigned SEGGER_RTT_HasData(unsigned BufferIndex) { SEGGER_RTT_BUFFER_DOWN* pRing; unsigned v; - pRing = &_SEGGER_RTT.aDown[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aDown[BufferIndex]; v = pRing->WrOff; return v - pRing->RdOff; } @@ -1526,7 +1526,7 @@ unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) { SEGGER_RTT_BUFFER_UP* pRing; unsigned v; - pRing = &_SEGGER_RTT.aUp[BufferIndex]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; v = pRing->RdOff; return pRing->WrOff - v; } @@ -1557,18 +1557,18 @@ int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned Buffer SEGGER_RTT_LOCK(); BufferIndex = 0; do { - if (_SEGGER_RTT.aDown[BufferIndex].pBuffer == NULL) { + if (_SEGGER_RTT_UNCACHED.aDown[BufferIndex].pBuffer == NULL) { break; } BufferIndex++; - } while (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers); - if (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers) { - _SEGGER_RTT.aDown[BufferIndex].sName = sName; - _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + } while (BufferIndex < _SEGGER_RTT_UNCACHED.MaxNumDownBuffers); + if (BufferIndex < _SEGGER_RTT_UNCACHED.MaxNumDownBuffers) { + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].sName = sName; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].RdOff = 0u; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].WrOff = 0u; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].Flags = Flags; } else { BufferIndex = -1; @@ -1603,18 +1603,18 @@ int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSi SEGGER_RTT_LOCK(); BufferIndex = 0; do { - if (_SEGGER_RTT.aUp[BufferIndex].pBuffer == NULL) { + if (_SEGGER_RTT_UNCACHED.aUp[BufferIndex].pBuffer == NULL) { break; } BufferIndex++; - } while (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers); - if (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers) { - _SEGGER_RTT.aUp[BufferIndex].sName = sName; - _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + } while (BufferIndex < _SEGGER_RTT_UNCACHED.MaxNumUpBuffers); + if (BufferIndex < _SEGGER_RTT_UNCACHED.MaxNumUpBuffers) { + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].sName = sName; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].RdOff = 0u; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].WrOff = 0u; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].Flags = Flags; } else { BufferIndex = -1; @@ -1653,16 +1653,16 @@ int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBu int r; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + if (BufferIndex < (unsigned)_SEGGER_RTT_UNCACHED.MaxNumUpBuffers) { SEGGER_RTT_LOCK(); if (BufferIndex > 0u) { - _SEGGER_RTT.aUp[BufferIndex].sName = sName; - _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].sName = sName; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].RdOff = 0u; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].WrOff = 0u; } - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } @@ -1702,16 +1702,16 @@ int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* p int r; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + if (BufferIndex < (unsigned)_SEGGER_RTT_UNCACHED.MaxNumDownBuffers) { SEGGER_RTT_LOCK(); if (BufferIndex > 0u) { - _SEGGER_RTT.aDown[BufferIndex].sName = sName; - _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer; - _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; - _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; - _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].sName = sName; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].RdOff = 0u; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].WrOff = 0u; } - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } @@ -1741,9 +1741,9 @@ int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) { int r; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + if (BufferIndex < (unsigned)_SEGGER_RTT_UNCACHED.MaxNumUpBuffers) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aUp[BufferIndex].sName = sName; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].sName = sName; SEGGER_RTT_UNLOCK(); r = 0; } @@ -1773,9 +1773,9 @@ int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { int r; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + if (BufferIndex < (unsigned)_SEGGER_RTT_UNCACHED.MaxNumDownBuffers) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aDown[BufferIndex].sName = sName; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].sName = sName; SEGGER_RTT_UNLOCK(); r = 0; } @@ -1805,9 +1805,9 @@ int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { int r; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + if (BufferIndex < (unsigned)_SEGGER_RTT_UNCACHED.MaxNumUpBuffers) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + _SEGGER_RTT_UNCACHED.aUp[BufferIndex].Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } @@ -1837,9 +1837,9 @@ int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) { int r; INIT(); - if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + if (BufferIndex < (unsigned)_SEGGER_RTT_UNCACHED.MaxNumDownBuffers) { SEGGER_RTT_LOCK(); - _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + _SEGGER_RTT_UNCACHED.aDown[BufferIndex].Flags = Flags; SEGGER_RTT_UNLOCK(); r = 0; } @@ -1888,7 +1888,8 @@ int SEGGER_RTT_SetTerminal(unsigned char TerminalId) { ac[0] = 0xFFu; if (TerminalId < sizeof(_aTerminalId)) { // We only support a certain number of channels ac[1] = _aTerminalId[TerminalId]; - pRing = &_SEGGER_RTT.aUp[0]; // Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed + pRing = &_SEGGER_RTT_UNCACHED + .aUp[0]; // Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { _ActiveTerminal = TerminalId; @@ -1943,7 +1944,7 @@ int SEGGER_RTT_TerminalOut(unsigned char TerminalId, const char* s) { // // Get "to-host" ring buffer. // - pRing = &_SEGGER_RTT.aUp[0]; + pRing = &_SEGGER_RTT_UNCACHED.aUp[0]; // // Need to be able to change terminal, write data, change back. // Compute the fixed and variable sizes. @@ -2021,7 +2022,7 @@ int SEGGER_RTT_TerminalOut(unsigned char TerminalId, const char* s) { * Number of bytes that are free in the selected up buffer. */ unsigned SEGGER_RTT_GetAvailWriteSpace(unsigned BufferIndex) { - return _GetAvailWriteSpace(&_SEGGER_RTT.aUp[BufferIndex]); + return _GetAvailWriteSpace(&_SEGGER_RTT_UNCACHED.aUp[BufferIndex]); } /********************************************************************* @@ -2045,13 +2046,13 @@ unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex) { // Avoid warnings regarding volatile access order. It's not a problem // in this case, but dampen compiler enthusiasm. // - RdOff = _SEGGER_RTT.aUp[BufferIndex].RdOff; - WrOff = _SEGGER_RTT.aUp[BufferIndex].WrOff; + RdOff = _SEGGER_RTT_UNCACHED.aUp[BufferIndex].RdOff; + WrOff = _SEGGER_RTT_UNCACHED.aUp[BufferIndex].WrOff; if (RdOff <= WrOff) { r = WrOff - RdOff; } else { - r = _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); + r = _SEGGER_RTT_UNCACHED.aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); } return r; } diff --git a/src/RTT/SEGGER_RTT.h b/src/RTT/SEGGER_RTT.h index 8e07ca5d1d..3b37d2a22f 100644 --- a/src/RTT/SEGGER_RTT.h +++ b/src/RTT/SEGGER_RTT.h @@ -49,7 +49,7 @@ ---------------------------END-OF-HEADER------------------------------ File : SEGGER_RTT.h Purpose : Implementation of SEGGER real-time transfer which allows - real-time communication on targets which support debugger + real-time communication on targets which support debugger memory accesses while the CPU is running. Revision: $Rev: 17697 $ ---------------------------------------------------------------------- @@ -225,7 +225,7 @@ unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex); // // Function macro for performance optimization // -#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT.aDown[n].WrOff - _SEGGER_RTT.aDown[n].RdOff) +#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT_UNCACHED.aDown[n].WrOff - _SEGGER_RTT_UNCACHED.aDown[n].RdOff) #if RTT_USE_ASM #define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock @@ -242,7 +242,7 @@ unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsign unsigned SEGGER_RTT_WriteDownBuffer(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); unsigned SEGGER_RTT_WriteDownBufferNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); -#define SEGGER_RTT_HASDATA_UP(n) (_SEGGER_RTT.aUp[n].WrOff - _SEGGER_RTT.aUp[n].RdOff) +#define SEGGER_RTT_HASDATA_UP(n) (_SEGGER_RTT_UNCACHED.aUp[n].WrOff - _SEGGER_RTT_UNCACHED.aUp[n].RdOff) /********************************************************************* * diff --git a/src/RTT/SEGGER_RTT_ASM_ARMv7M.S b/src/RTT/SEGGER_RTT_ASM_ARMv7M.S index 78cde4d758..db7a29a3cd 100644 --- a/src/RTT/SEGGER_RTT_ASM_ARMv7M.S +++ b/src/RTT/SEGGER_RTT_ASM_ARMv7M.S @@ -148,7 +148,7 @@ SEGGER_RTT_ASM_WriteSkipNoLock: // unsigned SEGGER_RTT_WriteSkipNoLock(unsigne // PUSH {R4-R7} ADD R3,R0,R0, LSL #+1 - LDR.W R0,=_SEGGER_RTT // pRing = &_SEGGER_RTT.aUp[BufferIndex]; + LDR.W R0,=_SEGGER_RTT_UNCACHED // pRing = &_SEGGER_RTT_UNCACHED.aUp[BufferIndex]; ADD R0,R0,R3, LSL #+3 ADD R6,R0,#+24 LDR R0,[R6, #+16] // RdOff = pRing->RdOff; diff --git a/src/RZA1/compiler/asm/reset_handler.S b/src/RZA1/compiler/asm/reset_handler.S index 1c8e0c7abc..35a9a75e1a 100644 --- a/src/RZA1/compiler/asm/reset_handler.S +++ b/src/RZA1/compiler/asm/reset_handler.S @@ -234,18 +234,17 @@ Finished: /* Other Handler */ /* ========================================================================= */ undefined_handler: - B undefined_handler - svc_handler: - B svc_handler - -prefetch_handler: - B prefetch_handler - abort_handler: - B abort_handler - +prefetch_handler: reserved_handler: - B reserved_handler + CPSID i /* Disable interrupt handling to preserve stack */ + MOV r0, LR /* Store SYS LR value as first function parameter */ + MOV r1, SP /* Store SYS SP value as second function parameter */ + CPS #USR_MODE /* Switch into user mode to get those register values */ + MOV r2, LR /* Store USR LR value as third function parameter */ + MOV r3, SP /* Store USR SP value as fourth function parameter */ + CPS #SYS_MODE /* Go back to SYS mode */ + LDR r12,=handle_cpu_fault /* Load address of handle_cpu_fault */ + BX r12 /* Jump to handle_cpu_fault without link */ .end - diff --git a/src/RZA1/diskio.c b/src/RZA1/diskio.c index 3da39d57a6..18f659fce0 100644 --- a/src/RZA1/diskio.c +++ b/src/RZA1/diskio.c @@ -203,7 +203,13 @@ DRESULT disk_read_without_streaming_first(BYTE pdrv, /* Physical drive nmuber to BYTE err; if (currentlyAccessingCard) - freezeWithError("E259"); // Operatricks got! But I think I fixed. + { + if (ALPHA_OR_BETA_VERSION) + { + // Operatricks got! But I think I fixed. + FREEZE_WITH_ERROR("E259"); + } + } //uint16_t startTime = MTU2.TCNT_0; @@ -247,7 +253,12 @@ DRESULT disk_write(BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE err; if (currentlyAccessingCard) - freezeWithError("E258"); + { + if (ALPHA_OR_BETA_VERSION) + { + FREEZE_WITH_ERROR("E258"); + } + } currentlyAccessingCard = 1; diff --git a/src/RZA1/intc/intc_handler.c b/src/RZA1/intc/intc_handler.c index 542e42987e..b7610c3a3c 100644 --- a/src/RZA1/intc/intc_handler.c +++ b/src/RZA1/intc/intc_handler.c @@ -108,7 +108,7 @@ void INTC_Handler_Interrupt(uint32_t icciar) if (int_id >= INTC_ID_TOTAL) /* In case of unsupported interrupt ID */ { // Insane thing that keeps happening - we get here somehow, with int_id 1023. - //freezeWithError("i029"); + //FREEZE_WITH_ERROR("i029"); uartPrintln("i029 ----------------------------------------------------!!"); return; // Just keep running - it seems to work at least most of the time? //Userdef_INTC_UndefId(int_id); // Previously, it'd just go in here and freeze. diff --git a/src/definitions.h b/src/definitions.h index 3a823ad84a..e3036837b2 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -1,7 +1,29 @@ #pragma once +#define ALPHA_OR_BETA_VERSION 1 // Whether to compile with additional error-checking + #include "RZA1/cpu_specific.h" #include "RZA1/system/r_typedefs.h" +#include "fault_handler.h" + +#ifdef __cplusplus +extern "C" { +#endif +// This is defined in display.cpp +extern void freezeWithError(char const* errmsg); +#ifdef __cplusplus +} +#endif + +#define FREEZE_WITH_ERROR(error) \ + ({ \ + uint32_t regLR = 0; \ + uint32_t regSP = 0; \ + asm volatile("MOV %0, LR\n" : "=r"(regLR)); \ + asm volatile("MOV %0, SP\n" : "=r"(regSP)); \ + fault_handler_print_freeze_pointers(0, 0, regLR, regSP); \ + freezeWithError(error); \ + }) #define TIMER_MIDI_GATE_OUTPUT 2 #define TIMER_SYSTEM_FAST 0 diff --git a/src/definitions_cxx.hpp b/src/definitions_cxx.hpp index f80aeaf1b5..be2a4fcef4 100644 --- a/src/definitions_cxx.hpp +++ b/src/definitions_cxx.hpp @@ -24,8 +24,6 @@ #include #include -#define ALPHA_OR_BETA_VERSION 1 // Whether to compile with additional error-checking - #define HARDWARE_TEST_MODE 0 #define AUTOMATED_TESTER_ENABLED (0 && ALPHA_OR_BETA_VERSION) @@ -356,7 +354,28 @@ constexpr int32_t kNumPatchSources = static_cast(kLastPatchSource); constexpr PatchSource kFirstLocalSource = PatchSource::ENVELOPE_0; //constexpr PatchSource kFirstUnchangeableSource = PatchSource::VELOCITY; -//Automation Instrument Clip View constants +//Menu Min Max Values + +//regular menu range e.g. 0 - 50 +constexpr int32_t kMaxMenuValue = 50; +constexpr int32_t kMinMenuValue = 0; +constexpr int32_t kMidMenuValue = kMinMenuValue + ((kMaxMenuValue - kMinMenuValue) / 2); + +//pan menu range e.g. -25 to +25 +constexpr int32_t kMaxMenuPanValue = kMaxMenuValue / 2; +constexpr int32_t kMinMenuPanValue = -1 * kMaxMenuPanValue; + +//patch cable menu range e.g. -5000 to 5000 +constexpr int32_t kMaxMenuPatchCableValue = kMaxMenuValue * 100; +constexpr int32_t kMinMenuPatchCableValue = -1 * kMaxMenuPatchCableValue; + +//metronome volume menu range : 22 to 27 +constexpr int32_t kMaxMenuMetronomeVolumeValue = 27; +constexpr int32_t kMinMenuMetronomeVolumeValue = 22; + +// + +//Automation View constants constexpr int32_t kNoSelection = 255; constexpr int32_t kNumNonKitAffectEntireParamsForAutomation = 55; constexpr int32_t kNumKitAffectEntireParamsForAutomation = 24; @@ -721,6 +740,13 @@ enum class ModFXParam { FEEDBACK, OFFSET, }; + +enum class CompParam { + RATIO, + ATTACK, + RELEASE, +}; + constexpr auto kNumModFXParams = util::to_underlying(ModFXParam::OFFSET) + 1; enum class PatchCableAcceptance { @@ -1090,3 +1116,10 @@ enum SessionLayoutType : uint8_t { SessionLayoutTypeGrid, SessionLayoutTypeMaxElement // Keep as boundary }; + +enum GridDefaultActiveMode : uint8_t { + GridDefaultActiveModeSelection, + GridDefaultActiveModeGreen, + GridDefaultActiveModeBlue, + GridDefaultActiveModeMaxElement // Keep as boundary +}; diff --git a/src/deluge/deluge.h b/src/deluge/deluge.h index beced6265b..11f78cbd5c 100644 --- a/src/deluge/deluge.h +++ b/src/deluge/deluge.h @@ -33,8 +33,6 @@ extern void loadAnyEnqueuedClustersRoutine(void); extern void logAudioAction(char const* string); -// This is defined in display.cpp -extern void freezeWithError(char const* errmsg); extern void consoleTextIfAllBootedUp(char const* text); extern void routineForSD(void); diff --git a/src/deluge/drivers/uart/uart.c b/src/deluge/drivers/uart/uart.c index b10416c437..4d768081da 100644 --- a/src/deluge/drivers/uart/uart.c +++ b/src/deluge/drivers/uart/uart.c @@ -192,6 +192,14 @@ int32_t uartGetTxBufferSpace(int32_t item) { return txBufferSizes[item] - uartGetTxBufferFullnessByItem(item); } +void uartDrain(uint32_t item) { + char value; + bool charReceived = true; + while (charReceived) { + charReceived = uartGetChar(item, (char*)&value); + } +} + void uartPutCharBack(int32_t item) { int32_t readPos = (uint32_t)rxBufferReadAddr[item] - ((uint32_t)rxBuffers[item]); readPos = (readPos - 1) & (rxBufferSizes[item] - 1); diff --git a/src/deluge/drivers/uart/uart.h b/src/deluge/drivers/uart/uart.h index 5efa5a1418..e6cae0ce79 100644 --- a/src/deluge/drivers/uart/uart.h +++ b/src/deluge/drivers/uart/uart.h @@ -60,5 +60,6 @@ void uartPrintFloat(float number); void uartFlushIfNotSending(int32_t item); int32_t uartGetTxBufferFullnessByItem(int32_t item); int32_t uartGetTxBufferSpace(int32_t item); +void uartDrain(uint32_t item); extern void tx_interrupt(int32_t item); diff --git a/src/deluge/dsp/compressor/compressor.cpp b/src/deluge/dsp/compressor/compressor.cpp index d129f40113..a61ce5ef17 100644 --- a/src/deluge/dsp/compressor/compressor.cpp +++ b/src/deluge/dsp/compressor/compressor.cpp @@ -25,6 +25,7 @@ Compressor::Compressor() { status = EnvelopeStage::OFF; lastValue = 2147483647; + envelopeOffset = ONE_Q31; pos = 0; follower = false; attack = getParamFromUserValue(Param::Static::COMPRESSOR_ATTACK, 7); @@ -231,7 +232,9 @@ int32_t Compressor::render(uint16_t numSamples, int32_t shapeValue) { //lastValue = 2147483647 - (((int64_t)((sineWave[((pos >> 14) + 256) & 1023] >> 1) + 1073741824) * (int64_t)envelopeHeight) >> 31); // Sine wave. Not great //lastValue = (multiply_32x32_rshift32(pos * (pos >> 15), envelopeHeight) << 1); // Parabola. Doesn't "punch". } - else { // Off + + else { // Off or hold + doOff: lastValue = envelopeOffset; } diff --git a/src/deluge/dsp/master_compressor/master_compressor.cpp b/src/deluge/dsp/master_compressor/master_compressor.cpp index 1e402b037f..ee15577fa4 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.cpp +++ b/src/deluge/dsp/master_compressor/master_compressor.cpp @@ -32,6 +32,7 @@ MasterCompressor::MasterCompressor() { shape = getParamFromUserValue(Param::Unpatched::COMPRESSOR_SHAPE, 1); //an appropriate range is 0-50*one q 15 threshold = ONE_Q31; + rawThreshold = 0; follower = true; //this is about a 1:1 ratio ratio = ONE_Q31 >> 1; @@ -64,6 +65,8 @@ void MasterCompressor::updateER() { } void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t volAdjustL, q31_t volAdjustR) { + ratio = (rawRatio >> 1) + (3 << 28); + threshold = ONE_Q31 - rawThreshold; updateER(); q31_t over = std::max(0, (meanVolume - threshdb) / 21) * ONE_Q31; @@ -74,7 +77,7 @@ void MasterCompressor::render(StereoSample* buffer, uint16_t numSamples, q31_t v registerHit(over); } out = Compressor::render(numSamples, shape); - out = (multiply_32x32_rshift32(out, ratio) << 1) + (multiply_32x32_rshift32(clip, ONE_Q31 - ratio)); + out = (multiply_32x32_rshift32(out, ratio) << 1) - (multiply_32x32_rshift32(clip, ONE_Q31 - ratio)); //out = multiply_32x32_rshift32(out, ratio) << 1; //21 is the max internal volume (i.e. one_q31) @@ -144,7 +147,7 @@ float MasterCompressor::calc_rms(StereoSample* buffer, uint16_t numSamples) { void MasterCompressor::setup(int32_t a, int32_t r, int32_t t, int32_t rat) { attack = a; release = r; - threshold = t; - ratio = rat; + rawThreshold = t; + rawRatio = rat; updateER(); } diff --git a/src/deluge/dsp/master_compressor/master_compressor.h b/src/deluge/dsp/master_compressor/master_compressor.h index b1b107aff1..4045021e68 100644 --- a/src/deluge/dsp/master_compressor/master_compressor.h +++ b/src/deluge/dsp/master_compressor/master_compressor.h @@ -37,6 +37,8 @@ class MasterCompressor : public Compressor { float calc_rms(StereoSample* buffer, uint16_t numSamples); uint8_t gainReduction; bool dither; + q31_t rawRatio; + q31_t rawThreshold; q31_t threshold; q31_t shape; q31_t ratio; diff --git a/src/deluge/dsp/timestretch/time_stretcher.cpp b/src/deluge/dsp/timestretch/time_stretcher.cpp index 9a84b8f2b0..34f31d9cae 100644 --- a/src/deluge/dsp/timestretch/time_stretcher.cpp +++ b/src/deluge/dsp/timestretch/time_stretcher.cpp @@ -247,7 +247,7 @@ bool TimeStretcher::hopEnd(SamplePlaybackGuide* guide, VoiceSample* voiceSample, // Trying to track down Steven's E133 - percCacheClusterNearby pointing to things with no reasons left for (int32_t l = 0; l < 2; l++) { if (percCacheClustersNearby[l] && !percCacheClustersNearby[l]->numReasonsToBeLoaded) { - display->freezeWithError("i036"); + FREEZE_WITH_ERROR("i036"); } } #endif @@ -621,7 +621,7 @@ bool TimeStretcher::hopEnd(SamplePlaybackGuide* guide, VoiceSample* voiceSample, int32_t newHeadTotals[TimeStretch::Crossfade::kNumMovingAverages]; if (ALPHA_OR_BETA_VERSION && newHeadBytePos < (int32_t)sample->audioDataStartPosBytes) { - display->freezeWithError("E285"); + FREEZE_WITH_ERROR("E285"); } success = sample->getAveragesForCrossfade(newHeadTotals, newHeadBytePos, crossfadeLengthSamplesSource, playDirection, lengthToAverageEach); @@ -1154,7 +1154,7 @@ void TimeStretcher::setupCrossfadeFromCache(SampleCache* cache, int32_t cacheByt Cluster* cacheCluster = cache->getCluster(cachedClusterIndex); if (ALPHA_OR_BETA_VERSION && !cacheCluster) { // If it got stolen - but we should have already detected this above - display->freezeWithError("E178"); + FREEZE_WITH_ERROR("E178"); } int32_t* __restrict__ readPos = (int32_t*)&cacheCluster->data[bytePosWithinCluster - 4 + kCacheByteDepth]; @@ -1198,7 +1198,7 @@ void TimeStretcher::setupCrossfadeFromCache(SampleCache* cache, int32_t cacheByt } if (ALPHA_OR_BETA_VERSION && numSamplesThisCacheRead <= 0) { - display->freezeWithError("E179"); + FREEZE_WITH_ERROR("E179"); } for (int32_t i = 0; i < numSamplesThisCacheRead; i++) { diff --git a/src/deluge/gui/context_menu/launch_style.cpp b/src/deluge/gui/context_menu/launch_style.cpp index c6388fda54..70d74e9950 100644 --- a/src/deluge/gui/context_menu/launch_style.cpp +++ b/src/deluge/gui/context_menu/launch_style.cpp @@ -50,9 +50,10 @@ bool LaunchStyle::setupAndCheckAvailability() { currentOption = static_cast(valueOption); -#if HAVE_OLED - scrollPos = currentOption; -#endif + if (display->haveOLED()) { + scrollPos = currentOption; + } + return true; } diff --git a/src/deluge/gui/l10n/english.cpp b/src/deluge/gui/l10n/english.cpp index c950bf7d86..56de967153 100644 --- a/src/deluge/gui/l10n/english.cpp +++ b/src/deluge/gui/l10n/english.cpp @@ -466,13 +466,17 @@ PLACE_SDRAM_DATA Language english{ {STRING_FOR_COMMANDS, "Commands"}, {STRING_FOR_OUTPUT, "Output"}, {STRING_FOR_DEFAULT_UI, "UI"}, + {STRING_FOR_DEFAULT_UI_GRID, "Grid"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE, "Default active mode"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_UNARM_EMPTY_PADS, "Empty pad unarm"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ALLOW_GREEN_SELECTION, "Select in green mode"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE_SELECTION, "Selection"}, {STRING_FOR_DEFAULT_UI_LAYOUT, "Layout"}, {STRING_FOR_DEFAULT_UI_KEYBOARD, "Keyboard"}, {STRING_FOR_DEFAULT_UI_KEYBOARD_LAYOUT_ISOMORPHIC, "Isomorphic"}, {STRING_FOR_DEFAULT_UI_KEYBOARD_LAYOUT_INKEY, "In-Key"}, {STRING_FOR_DEFAULT_UI_SONG, "Song"}, {STRING_FOR_DEFAULT_UI_SONG_LAYOUT_ROWS, "Rows"}, - {STRING_FOR_DEFAULT_UI_SONG_LAYOUT_GRID, "Grid"}, {STRING_FOR_INPUT, "Input"}, {STRING_FOR_TEMPO_MAGNITUDE_MATCHING, "Tempo magnitude matching"}, {STRING_FOR_TRIGGER_CLOCK, "Trigger clock"}, @@ -497,6 +501,7 @@ PLACE_SDRAM_DATA Language english{ {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_CLEAR_CLIP, "Clear Clip"}, {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_NUDGE_NOTE, "Nudge Note"}, {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_SHIFT_CLIP, "Shift Note"}, + {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_DISABLE_AUDITION_PAD_SHORTCUTS, "Disable Audition Pad Shortcuts"}, {STRING_FOR_COMMUNITY_FEATURE_DEV_SYSEX, "Allow Insecure Develop Sysex Messages"}, {STRING_FOR_COMMUNITY_FEATURE_SYNC_SCALING_ACTION, "Sync Scaling Action"}, {STRING_FOR_COMMUNITY_FEATURE_HIGHLIGHT_INCOMING_NOTES, "Highlight Incoming Notes"}, @@ -684,6 +689,8 @@ PLACE_SDRAM_DATA Language english{ {STRING_FOR_SIDECH_RELEASE_MENU_TITLE, "Sidech release"}, {STRING_FOR_SIDECHAIN_COMP_MENU_TITLE, "Sidechain comp"}, {STRING_FOR_NUM_MEMBER_CH_MENU_TITLE, "Num member ch."}, + {STRING_FOR_METRONOME, "METRONOME"}, + {STRING_FOR_DEFAULT_METRO_MENU_TITLE, "Default metro."}, {STRING_FOR_CV_INSTRUMENT, "CV instrument"}, diff --git a/src/deluge/gui/l10n/seven_segment.cpp b/src/deluge/gui/l10n/seven_segment.cpp index efba1db139..c16e43e8a5 100644 --- a/src/deluge/gui/l10n/seven_segment.cpp +++ b/src/deluge/gui/l10n/seven_segment.cpp @@ -308,13 +308,17 @@ PLACE_SDRAM_DATA Language seven_segment{ {STRING_FOR_COMMANDS, "CMD"}, {STRING_FOR_OUTPUT, "OUT"}, {STRING_FOR_DEFAULT_UI, "UI"}, + {STRING_FOR_DEFAULT_UI_GRID, "GRID"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE, "DEFMODE"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_UNARM_EMPTY_PADS, "UNARM"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ALLOW_GREEN_SELECTION, "GREENSELECT"}, + {STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE_SELECTION, "SELE"}, {STRING_FOR_DEFAULT_UI_LAYOUT, "LAYT"}, {STRING_FOR_DEFAULT_UI_KEYBOARD, "KBD"}, {STRING_FOR_DEFAULT_UI_KEYBOARD_LAYOUT_ISOMORPHIC, "ISO"}, {STRING_FOR_DEFAULT_UI_KEYBOARD_LAYOUT_INKEY, "INKY"}, {STRING_FOR_DEFAULT_UI_SONG, "SONG"}, {STRING_FOR_DEFAULT_UI_SONG_LAYOUT_ROWS, "ROWS"}, - {STRING_FOR_DEFAULT_UI_SONG_LAYOUT_GRID, "GRID"}, {STRING_FOR_INPUT, "IN"}, {STRING_FOR_TEMPO_MAGNITUDE_MATCHING, "MAGN"}, {STRING_FOR_TRIGGER_CLOCK, "TCLOCK"}, @@ -339,6 +343,7 @@ PLACE_SDRAM_DATA Language seven_segment{ {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_CLEAR_CLIP, "CLEA"}, {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_NUDGE_NOTE, "NUDG"}, {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_SHIFT_CLIP, "SHIF"}, + {STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_DISABLE_AUDITION_PAD_SHORTCUTS, "SCUT"}, {STRING_FOR_COMMUNITY_FEATURE_DEV_SYSEX, "SYSX"}, {STRING_FOR_COMMUNITY_FEATURE_SYNC_SCALING_ACTION, "SCAL"}, {STRING_FOR_COMMUNITY_FEATURE_HIGHLIGHT_INCOMING_NOTES, "HIGH"}, diff --git a/src/deluge/gui/l10n/strings.h b/src/deluge/gui/l10n/strings.h index ba13d03c79..8c312c8d22 100644 --- a/src/deluge/gui/l10n/strings.h +++ b/src/deluge/gui/l10n/strings.h @@ -373,13 +373,17 @@ enum class String : size_t { STRING_FOR_COMMANDS, STRING_FOR_OUTPUT, STRING_FOR_DEFAULT_UI, + STRING_FOR_DEFAULT_UI_GRID, + STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE, + STRING_FOR_DEFAULT_UI_DEFAULT_GRID_UNARM_EMPTY_PADS, + STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ALLOW_GREEN_SELECTION, + STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE_SELECTION, STRING_FOR_DEFAULT_UI_LAYOUT, STRING_FOR_DEFAULT_UI_KEYBOARD, STRING_FOR_DEFAULT_UI_KEYBOARD_LAYOUT_ISOMORPHIC, STRING_FOR_DEFAULT_UI_KEYBOARD_LAYOUT_INKEY, STRING_FOR_DEFAULT_UI_SONG, STRING_FOR_DEFAULT_UI_SONG_LAYOUT_ROWS, - STRING_FOR_DEFAULT_UI_SONG_LAYOUT_GRID, STRING_FOR_TEMPO_MAGNITUDE_MATCHING, STRING_FOR_TRIGGER_CLOCK, STRING_FOR_FM_MODULATOR_1, @@ -403,6 +407,7 @@ enum class String : size_t { STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_CLEAR_CLIP, STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_NUDGE_NOTE, STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_SHIFT_CLIP, + STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_DISABLE_AUDITION_PAD_SHORTCUTS, STRING_FOR_COMMUNITY_FEATURE_DEV_SYSEX, STRING_FOR_COMMUNITY_FEATURE_SYNC_SCALING_ACTION, STRING_FOR_COMMUNITY_FEATURE_HIGHLIGHT_INCOMING_NOTES, @@ -565,6 +570,7 @@ enum class String : size_t { STRING_FOR_SOUND, STRING_FOR_AUDIO_CLIP, STRING_FOR_SETTINGS, + STRING_FOR_METRONOME, // MENU TITLES STRING_FOR_ENV_ATTACK_MENU_TITLE, @@ -609,6 +615,7 @@ enum class String : size_t { STRING_FOR_MASTER_TRAN_MENU_TITLE, STRING_FOR_MIDI_INST_MENU_TITLE, STRING_FOR_NUM_MEMBER_CH_MENU_TITLE, + STRING_FOR_DEFAULT_METRO_MENU_TITLE, STRING_FOR_CV_INSTRUMENT, diff --git a/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h b/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h index cc676bb6f2..645fd12efa 100644 --- a/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h +++ b/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h @@ -27,13 +27,13 @@ class Gate final : public Integer { void readCurrentValue() override { auto* current_clip = static_cast(currentSong->currentClip); int64_t arp_gate = (int64_t)current_clip->arpeggiatorGate + 2147483648; - this->setValue((arp_gate * 50 + 2147483648) >> 32); + this->setValue((arp_gate * kMaxMenuValue + 2147483648) >> 32); } void writeCurrentValue() override { (static_cast(currentSong->currentClip))->arpeggiatorGate = (uint32_t)this->getValue() * 85899345 - 2147483648; } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } bool isRelevant(Sound* sound, int32_t whichThing) override { return soundEditor.editingCVOrMIDIClip(); } }; } // namespace deluge::gui::menu_item::arpeggiator::midi_cv diff --git a/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h b/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h index cc77b61ae3..a5915d049f 100644 --- a/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h +++ b/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h @@ -26,12 +26,13 @@ class Rate final : public Integer { using Integer::Integer; void readCurrentValue() override { this->setValue( - (((int64_t)(static_cast(currentSong->currentClip))->arpeggiatorRate + 2147483648) * 50 + (((int64_t)(static_cast(currentSong->currentClip))->arpeggiatorRate + 2147483648) + * kMaxMenuValue + 2147483648) >> 32); } void writeCurrentValue() override { - if (this->getValue() == 25) { + if (this->getValue() == kMidMenuValue) { (static_cast(currentSong->currentClip))->arpeggiatorRate = 0; } else { @@ -39,7 +40,7 @@ class Rate final : public Integer { (uint32_t)this->getValue() * 85899345 - 2147483648; } } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } bool isRelevant(Sound* sound, int32_t whichThing) override { return soundEditor.editingCVOrMIDIClip(); } }; } // namespace deluge::gui::menu_item::arpeggiator::midi_cv diff --git a/src/deluge/gui/menu_item/audio_clip/attack.h b/src/deluge/gui/menu_item/audio_clip/attack.h index ed2e793a43..bb356778de 100644 --- a/src/deluge/gui/menu_item/audio_clip/attack.h +++ b/src/deluge/gui/menu_item/audio_clip/attack.h @@ -27,13 +27,14 @@ class Attack final : public Integer { void readCurrentValue() override { this->setValue( - (((int64_t)(static_cast(currentSong->currentClip))->attack + 2147483648) * 50 + 2147483648) + (((int64_t)(static_cast(currentSong->currentClip))->attack + 2147483648) * kMaxMenuValue + + 2147483648) >> 32); } void writeCurrentValue() override { (static_cast(currentSong->currentClip))->attack = (uint32_t)this->getValue() * 85899345 - 2147483648; } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } }; } // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/audio_clip/hpf_freq.h b/src/deluge/gui/menu_item/audio_clip/hpf_freq.h index 47b3100a04..b276dd8807 100644 --- a/src/deluge/gui/menu_item/audio_clip/hpf_freq.h +++ b/src/deluge/gui/menu_item/audio_clip/hpf_freq.h @@ -25,7 +25,7 @@ class HPFFreq final : public UnpatchedParam { // 7SEG ONLY void drawValue() override { - if (this->getValue() == 0) { + if (this->getValue() == kMinMenuValue) { display->setText(l10n::get(l10n::String::STRING_FOR_DISABLED)); } else { diff --git a/src/deluge/gui/menu_item/audio_clip/lpf_freq.h b/src/deluge/gui/menu_item/audio_clip/lpf_freq.h index 33e7e68ab0..4085246105 100644 --- a/src/deluge/gui/menu_item/audio_clip/lpf_freq.h +++ b/src/deluge/gui/menu_item/audio_clip/lpf_freq.h @@ -25,7 +25,7 @@ class LPFFreq final : public UnpatchedParam { // 7Seg ONLY void drawValue() override { - if (this->getValue() == 50) { + if (this->getValue() == kMaxMenuValue) { display->setText(l10n::get(l10n::String::STRING_FOR_DISABLED)); } else { diff --git a/src/deluge/gui/menu_item/defaults/grid_allow_green_selection.h b/src/deluge/gui/menu_item/defaults/grid_allow_green_selection.h new file mode 100644 index 0000000000..f1a4df5e7a --- /dev/null +++ b/src/deluge/gui/menu_item/defaults/grid_allow_green_selection.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . +*/ +#pragma once +#include "gui/menu_item/toggle.h" + +namespace deluge::gui::menu_item::defaults { +class DefaultGridAllowGreenSelection final : public Toggle { +public: + using Toggle::Toggle; + void readCurrentValue() override { this->setValue(FlashStorage::gridAllowGreenSelection); } + void writeCurrentValue() override { FlashStorage::gridAllowGreenSelection = this->getValue(); } +}; +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/defaults/grid_default_active_mode.h b/src/deluge/gui/menu_item/defaults/grid_default_active_mode.h new file mode 100644 index 0000000000..693800356e --- /dev/null +++ b/src/deluge/gui/menu_item/defaults/grid_default_active_mode.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . +*/ +#pragma once +#include "definitions_cxx.hpp" +#include "gui/l10n/l10n.h" +#include "gui/l10n/strings.h" +#include "gui/menu_item/selection.h" +#include "hid/display/display.h" +#include "storage/flash_storage.h" +#include "util/misc.h" + +namespace deluge::gui::menu_item::defaults { +class DefaultGridDefaultActiveMode final : public Selection { +public: + using Selection::Selection; + void readCurrentValue() override { this->setValue(FlashStorage::defaultGridActiveMode); } + void writeCurrentValue() override { FlashStorage::defaultGridActiveMode = this->getValue(); } + std::vector getOptions() override { + return { + l10n::getView(l10n::String::STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE_SELECTION), + l10n::getView(l10n::String::STRING_FOR_GREEN), + l10n::getView(l10n::String::STRING_FOR_BLUE), + }; + } +}; +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/defaults/grid_unarm_empty_pads.h b/src/deluge/gui/menu_item/defaults/grid_unarm_empty_pads.h new file mode 100644 index 0000000000..1c416c9600 --- /dev/null +++ b/src/deluge/gui/menu_item/defaults/grid_unarm_empty_pads.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . +*/ +#pragma once +#include "gui/menu_item/toggle.h" + +namespace deluge::gui::menu_item::defaults { +class DefaultGridUnarmEmptyPads final : public Toggle { +public: + using Toggle::Toggle; + void readCurrentValue() override { this->setValue(FlashStorage::gridUnarmEmptyPads); } + void writeCurrentValue() override { FlashStorage::gridUnarmEmptyPads = this->getValue(); } +}; +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/defaults/metronome_volume.h b/src/deluge/gui/menu_item/defaults/metronome_volume.h new file mode 100644 index 0000000000..6b3f4c08ba --- /dev/null +++ b/src/deluge/gui/menu_item/defaults/metronome_volume.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . +*/ +#pragma once +#include "gui/menu_item/integer.h" +#include "storage/flash_storage.h" + +namespace deluge::gui::menu_item::defaults { +class MetronomeVolume final : public Integer { +public: + using Integer::Integer; + [[nodiscard]] int32_t getMinValue() const override { return kMinMenuMetronomeVolumeValue; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuMetronomeVolumeValue; } + void readCurrentValue() override { this->setValue(FlashStorage::defaultMetronomeVolume); } + void writeCurrentValue() override { FlashStorage::defaultMetronomeVolume = this->getValue(); } +}; +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/defaults/session_layout.h b/src/deluge/gui/menu_item/defaults/session_layout.h index be4a55fdb8..348a69f971 100644 --- a/src/deluge/gui/menu_item/defaults/session_layout.h +++ b/src/deluge/gui/menu_item/defaults/session_layout.h @@ -33,7 +33,7 @@ class SessionLayout final : public Selection { std::vector getOptions() override { return { l10n::getView(l10n::String::STRING_FOR_DEFAULT_UI_SONG_LAYOUT_ROWS), - l10n::getView(l10n::String::STRING_FOR_DEFAULT_UI_SONG_LAYOUT_GRID), + l10n::getView(l10n::String::STRING_FOR_DEFAULT_UI_GRID), }; } }; diff --git a/src/deluge/gui/menu_item/enumeration.cpp b/src/deluge/gui/menu_item/enumeration.cpp index f59a72f0d7..590e764368 100644 --- a/src/deluge/gui/menu_item/enumeration.cpp +++ b/src/deluge/gui/menu_item/enumeration.cpp @@ -3,32 +3,34 @@ namespace deluge::gui::menu_item { void Enumeration::beginSession(MenuItem* navigatedBackwardFrom) { Value::beginSession(navigatedBackwardFrom); -#if HAVE_OLED - soundEditor.menuCurrentScroll = 0; -#else - drawValue(); -#endif + if (display->haveOLED()) { + soundEditor.menuCurrentScroll = 0; + } + else { + drawValue(); + } } void Enumeration::selectEncoderAction(int32_t offset) { this->setValue(this->getValue() + offset); int32_t numOptions = size(); -#if HAVE_OLED - if (this->getValue() >= numOptions) { - this->setValue(numOptions - 1); - } - else if (this->getValue() < 0) { - this->setValue(0); - } -#else - if (this->getValue() >= numOptions) { - this->setValue(this->getValue() - numOptions); + if (display->haveOLED()) { + if (this->getValue() >= numOptions) { + this->setValue(numOptions - 1); + } + else if (this->getValue() < 0) { + this->setValue(0); + } } - else if (this->getValue() < 0) { - this->setValue(this->getValue() + numOptions); + else { + if (this->getValue() >= numOptions) { + this->setValue(this->getValue() - numOptions); + } + else if (this->getValue() < 0) { + this->setValue(this->getValue() + numOptions); + } } -#endif Value::selectEncoderAction(offset); } diff --git a/src/deluge/gui/menu_item/filter/hpf_freq.h b/src/deluge/gui/menu_item/filter/hpf_freq.h index 91979e8118..2241d64903 100644 --- a/src/deluge/gui/menu_item/filter/hpf_freq.h +++ b/src/deluge/gui/menu_item/filter/hpf_freq.h @@ -27,7 +27,7 @@ class HPFFreq final : public patched_param::IntegerNonFM { // 7Seg ONLY void drawValue() override { - if (this->getValue() == 0 + if (this->getValue() == kMinMenuValue && !soundEditor.currentParamManager->getPatchCableSet()->doesParamHaveSomethingPatchedToIt( ::Param::Local::HPF_FREQ)) { display->setText(l10n::get(l10n::String::STRING_FOR_DISABLED)); diff --git a/src/deluge/gui/menu_item/filter/lpf_freq.h b/src/deluge/gui/menu_item/filter/lpf_freq.h index 50b6121ac4..bb7125f3a5 100644 --- a/src/deluge/gui/menu_item/filter/lpf_freq.h +++ b/src/deluge/gui/menu_item/filter/lpf_freq.h @@ -26,7 +26,7 @@ class LPFFreq final : public patched_param::IntegerNonFM { // 7Seg ONLY void drawValue() override { - if (this->getValue() == 50 + if (this->getValue() == kMaxMenuValue && !soundEditor.currentParamManager->getPatchCableSet()->doesParamHaveSomethingPatchedToIt( ::Param::Local::LPF_FREQ)) { display->setText(l10n::get(l10n::String::STRING_FOR_DISABLED)); diff --git a/src/deluge/gui/menu_item/menu_item.h b/src/deluge/gui/menu_item/menu_item.h index be37321a85..2757719996 100644 --- a/src/deluge/gui/menu_item/menu_item.h +++ b/src/deluge/gui/menu_item/menu_item.h @@ -95,7 +95,7 @@ class MenuItem { /// /// The returned pointer must live long enough for us to draw the title, which for practical purposes means "the /// lifetime of this menu item" - [[nodiscard]] virtual std::string_view getTitle() const { return deluge::l10n::getView(name); } + [[nodiscard]] virtual std::string_view getTitle() const { return deluge::l10n::getView(title); } virtual void renderOLED(); virtual void drawPixelsForOled() {} diff --git a/src/deluge/gui/menu_item/midi/default_velocity_to_level.h b/src/deluge/gui/menu_item/midi/default_velocity_to_level.h index 7475715426..36702de590 100644 --- a/src/deluge/gui/menu_item/midi/default_velocity_to_level.h +++ b/src/deluge/gui/menu_item/midi/default_velocity_to_level.h @@ -24,12 +24,13 @@ namespace deluge::gui::menu_item::midi { class DefaultVelocityToLevel final : public IntegerWithOff { public: using IntegerWithOff::IntegerWithOff; - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } void readCurrentValue() override { - this->setValue(((int64_t)soundEditor.currentMIDIDevice->defaultVelocityToLevel * 50 + 536870912) >> 30); + this->setValue(((int64_t)soundEditor.currentMIDIDevice->defaultVelocityToLevel * kMaxMenuValue + 536870912) + >> 30); } void writeCurrentValue() override { - soundEditor.currentMIDIDevice->defaultVelocityToLevel = this->getValue() * 21474836; + soundEditor.currentMIDIDevice->defaultVelocityToLevel = this->getValue() * (2147483648 / (kMaxMenuValue * 2)); currentSong->grabVelocityToLevelFromMIDIDeviceAndSetupPatchingForEverything(soundEditor.currentMIDIDevice); MIDIDeviceManager::anyChangesToSave = true; } diff --git a/src/deluge/gui/menu_item/osc/pulse_width.h b/src/deluge/gui/menu_item/osc/pulse_width.h index 8aa639a18d..8242e56363 100644 --- a/src/deluge/gui/menu_item/osc/pulse_width.h +++ b/src/deluge/gui/menu_item/osc/pulse_width.h @@ -29,11 +29,22 @@ class PulseWidth final : public menu_item::source::PatchedParam, public Formatte [[nodiscard]] std::string_view getTitle() const override { return FormattedTitle::title(); } - int32_t getFinalValue() override { return (uint32_t)this->getValue() * (85899345 >> 1); } + int32_t getFinalValue() override { + if (this->getValue() == kMaxMenuValue) { + return 2147483647; + } + else if (this->getValue() == kMinMenuValue) { + return 0; + } + else { + return (uint32_t)this->getValue() * (2147483648 / kMidMenuValue) >> 1; + } + } void readCurrentValue() override { this->setValue( - ((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) * 100 + 2147483648) + ((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) * (kMaxMenuValue * 2) + + 2147483648) >> 32); } diff --git a/src/deluge/gui/menu_item/param.h b/src/deluge/gui/menu_item/param.h index 3ea4080580..0e0211a043 100644 --- a/src/deluge/gui/menu_item/param.h +++ b/src/deluge/gui/menu_item/param.h @@ -28,8 +28,8 @@ namespace deluge::gui::menu_item { class Param { public: Param(int32_t newP = 0) : p(newP) {} - [[nodiscard]] virtual int32_t getMaxValue() const { return 50; } - [[nodiscard]] virtual int32_t getMinValue() const { return 0; } + [[nodiscard]] virtual int32_t getMaxValue() const { return kMaxMenuValue; } + [[nodiscard]] virtual int32_t getMinValue() const { return kMinMenuValue; } virtual uint8_t getP() { return p; }; MenuItem* selectButtonPress(); virtual ModelStackWithAutoParam* getModelStack(void* memory) = 0; diff --git a/src/deluge/gui/menu_item/patch_cable_strength.cpp b/src/deluge/gui/menu_item/patch_cable_strength.cpp index 3c7059e588..5498af8467 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength.cpp +++ b/src/deluge/gui/menu_item/patch_cable_strength.cpp @@ -112,7 +112,7 @@ void PatchCableStrength::renderOLED() { char buffer[12]; if (preferBarDrawing) { - int32_t rounded = (this->getValue() + 50 * (this->getValue() > 0 ? 1 : -1)) / 100; + int32_t rounded = this->getValue() / 100; intToString(rounded, buffer, 1); deluge::hid::display::OLED::drawStringAlignRight( buffer, extraY + OLED_MAIN_TOPMOST_PIXEL + 4 + destinationDescriptor.isJustAParam(), @@ -152,7 +152,7 @@ void PatchCableStrength::readCurrentValue() { int32_t paramValue = patchCableSet->patchCables[c].param.getCurrentValue(); // the internal values are stored in the range -(2^30) to 2^30. // rescale them to the range -5000 to 5000 and round to nearest. - this->setValue(((int64_t)paramValue * 5000 + (1 << 29)) >> 30); + this->setValue(((int64_t)paramValue * kMaxMenuPatchCableValue + (1 << 29)) >> 30); } } @@ -175,8 +175,9 @@ void PatchCableStrength::writeCurrentValue() { return; } - // rescale from 5000 to 2**30. The magic constant is ((2^30)/5000), shifted 32 bits for precision ((1<<(30+32))/5000) - int32_t finalValue = ((int64_t)922337203685477 * this->getValue()) >> 32; + //rescale from 5000 to 2^30. The magic constant is ((2^30)/5000), shifted 32 bits for precision ((1<<(30+32))/5000) + int64_t magicConstant = (922337203685477 * 5000) / kMaxMenuPatchCableValue; + int32_t finalValue = (magicConstant * this->getValue()) >> 32; modelStackWithParam->autoParam->setCurrentValueInResponseToUserInput(finalValue, modelStackWithParam); } diff --git a/src/deluge/gui/menu_item/patch_cable_strength.h b/src/deluge/gui/menu_item/patch_cable_strength.h index ba0892d83f..c36b37f7c3 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength.h +++ b/src/deluge/gui/menu_item/patch_cable_strength.h @@ -27,8 +27,8 @@ class PatchCableStrength : public Decimal, public MenuItemWithCCLearning { void beginSession(MenuItem* navigatedBackwardFrom) final; void readCurrentValue() final; void writeCurrentValue() override; - [[nodiscard]] int32_t getMinValue() const final { return -5000; } - [[nodiscard]] int32_t getMaxValue() const final { return 5000; } + [[nodiscard]] int32_t getMinValue() const final { return kMinMenuPatchCableValue; } + [[nodiscard]] int32_t getMaxValue() const final { return kMaxMenuPatchCableValue; } [[nodiscard]] int32_t getNumDecimalPlaces() const final { return 2; } virtual int32_t getDefaultEditPos() { return 2; } MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) override; diff --git a/src/deluge/gui/menu_item/patch_cables.cpp b/src/deluge/gui/menu_item/patch_cables.cpp index acc269baf5..c5bf5f4aed 100644 --- a/src/deluge/gui/menu_item/patch_cables.cpp +++ b/src/deluge/gui/menu_item/patch_cables.cpp @@ -79,7 +79,7 @@ void PatchCables::renderOptions() { } int32_t param_value = cable->param.getCurrentValue(); - int32_t level = ((int64_t)param_value * 5000 + (1 << 29)) >> 30; + int32_t level = ((int64_t)param_value * kMaxMenuPatchCableValue + (1 << 29)) >> 30; floatToString((float)level / 100, buf + off + 5, 2, 2); //fmt::vformat_to_n(buf + off + 5, 5, "{:4}", fmt::make_format_args(); diff --git a/src/deluge/gui/menu_item/patched_param/integer.cpp b/src/deluge/gui/menu_item/patched_param/integer.cpp index 155a2d048b..19785c6cc3 100644 --- a/src/deluge/gui/menu_item/patched_param/integer.cpp +++ b/src/deluge/gui/menu_item/patched_param/integer.cpp @@ -21,9 +21,10 @@ namespace deluge::gui::menu_item::patched_param { void Integer::readCurrentValue() { - this->setValue((((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) + 2147483648) * 50 - + 2147483648) - >> 32); + this->setValue( + (((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) + 2147483648) * kMaxMenuValue + + 2147483648) + >> 32); } void Integer::writeCurrentValue() { @@ -35,10 +36,15 @@ void Integer::writeCurrentValue() { } int32_t Integer::getFinalValue() { - if (this->getValue() == 25) { - return 0; + if (this->getValue() == kMaxMenuValue) { + return 2147483647; + } + else if (this->getValue() == kMinMenuValue) { + return -2147483648; + } + else { + return (uint32_t)this->getValue() * (2147483648 / kMidMenuValue) - 2147483648; } - return (uint32_t)this->getValue() * 85899345 - 2147483648; } } // namespace deluge::gui::menu_item::patched_param diff --git a/src/deluge/gui/menu_item/patched_param/pan.cpp b/src/deluge/gui/menu_item/patched_param/pan.cpp index 93bc87be8f..178e7d59d6 100644 --- a/src/deluge/gui/menu_item/patched_param/pan.cpp +++ b/src/deluge/gui/menu_item/patched_param/pan.cpp @@ -47,17 +47,21 @@ void Pan::drawValue() { } int32_t Pan::getFinalValue() { - if (this->getValue() == 32) { + if (this->getValue() == kMaxMenuPanValue) { return 2147483647; } - if (this->getValue() == -32) { + else if (this->getValue() == kMinMenuPanValue) { return -2147483648; } - return ((int32_t)this->getValue() * 33554432 * 2); + else { + return ((int32_t)this->getValue() * (2147483648 / (kMaxMenuPanValue * 2)) * 2); + } } void Pan::readCurrentValue() { - this->setValue(((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) * 64 + 2147483648) - >> 32); + this->setValue( + ((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) * (kMaxMenuPanValue * 2) + + 2147483648) + >> 32); } } // namespace deluge::gui::menu_item::patched_param diff --git a/src/deluge/gui/menu_item/patched_param/pan.h b/src/deluge/gui/menu_item/patched_param/pan.h index 1d44d61a14..c6d61afe5d 100644 --- a/src/deluge/gui/menu_item/patched_param/pan.h +++ b/src/deluge/gui/menu_item/patched_param/pan.h @@ -24,8 +24,8 @@ class Pan : public Integer { void drawValue() override; protected: - [[nodiscard]] int32_t getMaxValue() const override { return 32; } - [[nodiscard]] int32_t getMinValue() const override { return -32; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuPanValue; } + [[nodiscard]] int32_t getMinValue() const override { return kMinMenuPanValue; } int32_t getFinalValue() override; void readCurrentValue() override; }; diff --git a/src/deluge/gui/menu_item/reverb/compressor/shape.h b/src/deluge/gui/menu_item/reverb/compressor/shape.h index 29a1579e32..8e11736f6e 100644 --- a/src/deluge/gui/menu_item/reverb/compressor/shape.h +++ b/src/deluge/gui/menu_item/reverb/compressor/shape.h @@ -26,13 +26,13 @@ class Shape final : public Integer { public: using Integer::Integer; void readCurrentValue() override { - this->setValue((((int64_t)AudioEngine::reverbCompressorShape + 2147483648) * 50 + 2147483648) >> 32); + this->setValue((((int64_t)AudioEngine::reverbCompressorShape + 2147483648) * kMaxMenuValue + 2147483648) >> 32); } void writeCurrentValue() override { AudioEngine::reverbCompressorShape = (uint32_t)this->getValue() * 85899345 - 2147483648; AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } bool isRelevant(Sound* sound, int32_t whichThing) override { return (AudioEngine::reverbCompressorVolume >= 0); } }; } // namespace deluge::gui::menu_item::reverb::compressor diff --git a/src/deluge/gui/menu_item/reverb/compressor/volume.h b/src/deluge/gui/menu_item/reverb/compressor/volume.h index 7af983e7cc..813fdfd615 100644 --- a/src/deluge/gui/menu_item/reverb/compressor/volume.h +++ b/src/deluge/gui/menu_item/reverb/compressor/volume.h @@ -30,7 +30,7 @@ class Volume final : public Integer { AudioEngine::reverbCompressorVolume = this->getValue() * 21474836; AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } [[nodiscard]] int32_t getMinValue() const override { return -1; } void drawValue() override { diff --git a/src/deluge/gui/menu_item/reverb/dampening.h b/src/deluge/gui/menu_item/reverb/dampening.h index 4a1874f3a9..35ae79d784 100644 --- a/src/deluge/gui/menu_item/reverb/dampening.h +++ b/src/deluge/gui/menu_item/reverb/dampening.h @@ -25,8 +25,8 @@ namespace deluge::gui::menu_item::reverb { class Dampening final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { this->setValue(std::round(AudioEngine::reverb.getdamp() * 50)); } - void writeCurrentValue() override { AudioEngine::reverb.setdamp((float)this->getValue() / 50); } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + void readCurrentValue() override { this->setValue(std::round(AudioEngine::reverb.getdamp() * kMaxMenuValue)); } + void writeCurrentValue() override { AudioEngine::reverb.setdamp((float)this->getValue() / kMaxMenuValue); } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } }; } // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/reverb/pan.h b/src/deluge/gui/menu_item/reverb/pan.h index abe4c3cb4c..3c52c02b1f 100644 --- a/src/deluge/gui/menu_item/reverb/pan.h +++ b/src/deluge/gui/menu_item/reverb/pan.h @@ -43,8 +43,10 @@ class Pan final : public Integer { void writeCurrentValue() override { AudioEngine::reverbPan = ((int32_t)this->getValue() * 33554432); } - void readCurrentValue() override { this->setValue(((int64_t)AudioEngine::reverbPan * 128 + 2147483648) >> 32); } - [[nodiscard]] int32_t getMaxValue() const override { return 32; } - [[nodiscard]] int32_t getMinValue() const override { return -32; } + void readCurrentValue() override { + this->setValue(((int64_t)AudioEngine::reverbPan * (kMaxMenuPanValue * 4) + 2147483648) >> 32); + } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuPanValue; } + [[nodiscard]] int32_t getMinValue() const override { return kMinMenuPanValue; } }; } // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/reverb/room_size.h b/src/deluge/gui/menu_item/reverb/room_size.h index ed42469f58..0a31e8524f 100644 --- a/src/deluge/gui/menu_item/reverb/room_size.h +++ b/src/deluge/gui/menu_item/reverb/room_size.h @@ -25,8 +25,8 @@ namespace deluge::gui::menu_item::reverb { class RoomSize final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { this->setValue(std::round(AudioEngine::reverb.getroomsize() * 50)); } - void writeCurrentValue() override { AudioEngine::reverb.setroomsize((float)this->getValue() / 50); } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + void readCurrentValue() override { this->setValue(std::round(AudioEngine::reverb.getroomsize() * kMaxMenuValue)); } + void writeCurrentValue() override { AudioEngine::reverb.setroomsize((float)this->getValue() / kMaxMenuValue); } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } }; } // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/reverb/width.h b/src/deluge/gui/menu_item/reverb/width.h index 127d022792..ac56279de6 100644 --- a/src/deluge/gui/menu_item/reverb/width.h +++ b/src/deluge/gui/menu_item/reverb/width.h @@ -25,8 +25,8 @@ namespace deluge::gui::menu_item::reverb { class Width final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { this->setValue(std::round(AudioEngine::reverb.getwidth() * 50)); } - void writeCurrentValue() override { AudioEngine::reverb.setwidth((float)this->getValue() / 50); } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + void readCurrentValue() override { this->setValue(std::round(AudioEngine::reverb.getwidth() * kMaxMenuValue)); } + void writeCurrentValue() override { AudioEngine::reverb.setwidth((float)this->getValue() / kMaxMenuValue); } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } }; } // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/runtime_feature/settings.cpp b/src/deluge/gui/menu_item/runtime_feature/settings.cpp index f253ab0eba..15a4bc2c65 100644 --- a/src/deluge/gui/menu_item/runtime_feature/settings.cpp +++ b/src/deluge/gui/menu_item/runtime_feature/settings.cpp @@ -44,6 +44,7 @@ Setting menuAutomationInterpolate(RuntimeFeatureSettingType::AutomationInterpola Setting menuAutomationClearClip(RuntimeFeatureSettingType::AutomationClearClip); Setting menuAutomationNudgeNote(RuntimeFeatureSettingType::AutomationNudgeNote); Setting menuAutomationShiftClip(RuntimeFeatureSettingType::AutomationShiftClip); +Setting menuAutomationDisableAuditionPadShortcuts(RuntimeFeatureSettingType::AutomationDisableAuditionPadShortcuts); Setting menuSyncScalingAction(RuntimeFeatureSettingType::SyncScalingAction); DevSysexSetting menuDevSysexAllowed(RuntimeFeatureSettingType::DevSysexAllowed); Setting menuHighlightIncomingNotes(RuntimeFeatureSettingType::HighlightIncomingNotes); @@ -58,6 +59,7 @@ Submenu subMenuAutomation{ &menuAutomationClearClip, &menuAutomationNudgeNote, &menuAutomationShiftClip, + &menuAutomationDisableAuditionPadShortcuts, }, }; diff --git a/src/deluge/gui/menu_item/runtime_feature/settings.h b/src/deluge/gui/menu_item/runtime_feature/settings.h index a67581dc16..dea0ec8c20 100644 --- a/src/deluge/gui/menu_item/runtime_feature/settings.h +++ b/src/deluge/gui/menu_item/runtime_feature/settings.h @@ -24,7 +24,7 @@ namespace deluge::gui::menu_item::runtime_feature { /// Some runtime feature settings are squirrled away in submenus. -constexpr size_t kNonTopLevelSettings = 3; +constexpr size_t kNonTopLevelSettings = 4; // RuntimeFeatureSettingType::MaxElement - kNonTopLevelSettings class Settings final : public Submenu { public: diff --git a/src/deluge/gui/menu_item/selection.cpp b/src/deluge/gui/menu_item/selection.cpp index 5f0c6fe78e..95efd6d39a 100644 --- a/src/deluge/gui/menu_item/selection.cpp +++ b/src/deluge/gui/menu_item/selection.cpp @@ -20,7 +20,7 @@ void Selection::drawPixelsForOled() { if (soundEditor.menuCurrentScroll > value) { soundEditor.menuCurrentScroll = value; } - else if (soundEditor.menuCurrentScroll < this->getValue() - kOLEDMenuNumOptionsVisible + 1) { + else if (soundEditor.menuCurrentScroll < value - kOLEDMenuNumOptionsVisible + 1) { soundEditor.menuCurrentScroll = value - kOLEDMenuNumOptionsVisible + 1; } diff --git a/src/deluge/gui/menu_item/sidechain/send.h b/src/deluge/gui/menu_item/sidechain/send.h index ef40660a07..b00f00ad42 100644 --- a/src/deluge/gui/menu_item/sidechain/send.h +++ b/src/deluge/gui/menu_item/sidechain/send.h @@ -24,17 +24,17 @@ class Send final : public Integer { public: using Integer::Integer; void readCurrentValue() override { - this->setValue(((uint64_t)soundEditor.currentSound->sideChainSendLevel * 50 + 1073741824) >> 31); + this->setValue(((uint64_t)soundEditor.currentSound->sideChainSendLevel * kMaxMenuValue + 1073741824) >> 31); } void writeCurrentValue() override { - if (this->getValue() == 50) { + if (this->getValue() == kMaxMenuValue) { soundEditor.currentSound->sideChainSendLevel = 2147483647; } else { soundEditor.currentSound->sideChainSendLevel = this->getValue() * 42949673; } } - [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuValue; } bool isRelevant(Sound* sound, int32_t whichThing) override { return (soundEditor.editingKit()); } }; } // namespace deluge::gui::menu_item::sidechain diff --git a/src/deluge/gui/menu_item/submenu.cpp b/src/deluge/gui/menu_item/submenu.cpp index a8a1664fc0..c6af85d88d 100644 --- a/src/deluge/gui/menu_item/submenu.cpp +++ b/src/deluge/gui/menu_item/submenu.cpp @@ -66,45 +66,47 @@ void Submenu::drawPixelsForOled() { } void Submenu::selectEncoderAction(int32_t offset) { - + int32_t sign = (offset > 0) ? 1 : ((offset < 0) ? -1 : 0); auto thisSubmenuItem = current_item_; - do { - if (offset >= 0) { - thisSubmenuItem++; - if (thisSubmenuItem == items.end()) { - if (display->haveOLED()) { - return; - } - else { + for (size_t i = 0; i < std::abs(offset); ++i) { + do { + if (offset >= 0) { + thisSubmenuItem++; + if (thisSubmenuItem >= items.end()) { + if (display->haveOLED()) { + updateDisplay(); + return; + } + // 7SEG wraps thisSubmenuItem = items.begin(); } } - } - else { - if (thisSubmenuItem == items.begin()) { - if (display->haveOLED()) { - return; + else { + if (thisSubmenuItem <= items.begin()) { + if (display->haveOLED()) { + updateDisplay(); + return; + } + // 7SEG wraps + thisSubmenuItem = (items.end() - 1); } else { - thisSubmenuItem = (items.end() - 1); + thisSubmenuItem--; } } - else { - thisSubmenuItem--; - } - } - } while (!(*thisSubmenuItem)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)); + } while (!(*thisSubmenuItem)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)); - current_item_ = thisSubmenuItem; + current_item_ = thisSubmenuItem; - if (display->haveOLED()) { - soundEditor.menuCurrentScroll += offset; - if (soundEditor.menuCurrentScroll < 0) { - soundEditor.menuCurrentScroll = 0; - } - else if (soundEditor.menuCurrentScroll > kOLEDMenuNumOptionsVisible - 1) { - soundEditor.menuCurrentScroll = kOLEDMenuNumOptionsVisible - 1; + if (display->haveOLED()) { + soundEditor.menuCurrentScroll += sign; + if (soundEditor.menuCurrentScroll < 0) { + soundEditor.menuCurrentScroll = 0; + } + else if (soundEditor.menuCurrentScroll > kOLEDMenuNumOptionsVisible - 1) { + soundEditor.menuCurrentScroll = kOLEDMenuNumOptionsVisible - 1; + } } } diff --git a/src/deluge/gui/menu_item/unpatched_param.cpp b/src/deluge/gui/menu_item/unpatched_param.cpp index e18cc71a35..f87d584ae3 100644 --- a/src/deluge/gui/menu_item/unpatched_param.cpp +++ b/src/deluge/gui/menu_item/unpatched_param.cpp @@ -31,10 +31,10 @@ extern "C" { namespace deluge::gui::menu_item { void UnpatchedParam::readCurrentValue() { - this->setValue( - (((int64_t)soundEditor.currentParamManager->getUnpatchedParamSet()->getValue(getP()) + 2147483648) * 50 - + 2147483648) - >> 32); + this->setValue((((int64_t)soundEditor.currentParamManager->getUnpatchedParamSet()->getValue(getP()) + 2147483648) + * kMaxMenuValue + + 2147483648) + >> 32); } ModelStackWithAutoParam* UnpatchedParam::getModelStack(void* memory) { @@ -52,11 +52,14 @@ void UnpatchedParam::writeCurrentValue() { } int32_t UnpatchedParam::getFinalValue() { - if (this->getValue() == 25) { - return 0; + if (this->getValue() == kMaxMenuValue) { + return 2147483647; + } + else if (this->getValue() == kMinMenuValue) { + return -2147483648; } else { - return (uint32_t)this->getValue() * 85899345 - 2147483648; + return (uint32_t)this->getValue() * (2147483648 / kMidMenuValue) - 2147483648; } } diff --git a/src/deluge/gui/menu_item/unpatched_param/pan.cpp b/src/deluge/gui/menu_item/unpatched_param/pan.cpp index 8c29436630..dd19bff0d5 100644 --- a/src/deluge/gui/menu_item/unpatched_param/pan.cpp +++ b/src/deluge/gui/menu_item/unpatched_param/pan.cpp @@ -42,20 +42,22 @@ void Pan::drawValue() { // TODO: should really combine this with the "patched } int32_t Pan::getFinalValue() { - if (this->getValue() == 32) { + if (this->getValue() == kMaxMenuPanValue) { return 2147483647; } - else if (this->getValue() == -32) { + else if (this->getValue() == kMinMenuPanValue) { return -2147483648; } else { - return ((int32_t)this->getValue() * 33554432 * 2); + return ((int32_t)this->getValue() * (2147483648 / (kMaxMenuPanValue * 2)) * 2); } } void Pan::readCurrentValue() { this->setValue( - ((int64_t)soundEditor.currentParamManager->getUnpatchedParamSet()->getValue(getP()) * 64 + 2147483648) >> 32); + ((int64_t)soundEditor.currentParamManager->getUnpatchedParamSet()->getValue(getP()) * (kMaxMenuPanValue * 2) + + 2147483648) + >> 32); } } // namespace deluge::gui::menu_item::unpatched_param diff --git a/src/deluge/gui/menu_item/unpatched_param/pan.h b/src/deluge/gui/menu_item/unpatched_param/pan.h index 9ec2351bb9..a191227021 100644 --- a/src/deluge/gui/menu_item/unpatched_param/pan.h +++ b/src/deluge/gui/menu_item/unpatched_param/pan.h @@ -26,8 +26,8 @@ class Pan final : public UnpatchedParam { virtual void drawValue(); protected: - [[nodiscard]] int32_t getMaxValue() const override { return 32; } - [[nodiscard]] int32_t getMinValue() const override { return -32; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxMenuPanValue; } + [[nodiscard]] int32_t getMinValue() const override { return kMinMenuPanValue; } int32_t getFinalValue() override; void readCurrentValue() override; }; diff --git a/src/deluge/gui/ui/audio_recorder.cpp b/src/deluge/gui/ui/audio_recorder.cpp index 717c2a0421..9a66345017 100644 --- a/src/deluge/gui/ui/audio_recorder.cpp +++ b/src/deluge/gui/ui/audio_recorder.cpp @@ -147,7 +147,7 @@ bool AudioRecorder::setupRecordingToFile(AudioInputChannel newMode, int32_t newN AudioRecordingFolder folderID) { if (ALPHA_OR_BETA_VERSION && recordingSource > AudioInputChannel::NONE) { - display->freezeWithError("E242"); + FREEZE_WITH_ERROR("E242"); } recorder = AudioEngine::getNewRecorder(newNumChannels, folderID, newMode, kInternalButtonPressLatency); diff --git a/src/deluge/gui/ui/browser/browser.cpp b/src/deluge/gui/ui/browser/browser.cpp index 0724be56dc..9db7925a31 100644 --- a/src/deluge/gui/ui/browser/browser.cpp +++ b/src/deluge/gui/ui/browser/browser.cpp @@ -720,7 +720,7 @@ int32_t Browser::arrivedInNewFolder(int32_t direction, char const* filenameToSta int32_t searchResult = fileItems.search(endSearchString.get()); #if ALPHA_OR_BETA_VERSION if (searchResult <= 0) { - display->freezeWithError("E448"); + FREEZE_WITH_ERROR("E448"); error = ERROR_BUG; goto gotErrorAfterAllocating; } diff --git a/src/deluge/gui/ui/browser/sample_browser.cpp b/src/deluge/gui/ui/browser/sample_browser.cpp index 5f65546bcb..ea10d7053e 100644 --- a/src/deluge/gui/ui/browser/sample_browser.cpp +++ b/src/deluge/gui/ui/browser/sample_browser.cpp @@ -838,7 +838,7 @@ bool SampleBrowser::claimCurrentFile(int32_t mayDoPitchDetection, int32_t mayDoS if (soundEditor.currentSource->ranges.getNumElements() > 1 && soundEditor.currentSource->oscType == OscType::SAMPLE) { #if ALPHA_OR_BETA_VERSION - if (mayDoWaveTable == 2) display->freezeWithError("E425"); + if (mayDoWaveTable == 2) FREEZE_WITH_ERROR("E425"); #endif goto doLoadAsSample; } @@ -900,7 +900,7 @@ bool SampleBrowser::claimCurrentFile(int32_t mayDoPitchDetection, int32_t mayDoS if (soundEditor.currentSource->ranges.getNumElements() > 1 && soundEditor.currentSource->oscType == OscType::WAVETABLE) { #if ALPHA_OR_BETA_VERSION - if (!mayDoWaveTable) display->freezeWithError("E426"); + if (!mayDoWaveTable) FREEZE_WITH_ERROR("E426"); #endif goto doLoadAsWaveTable; } @@ -1214,7 +1214,7 @@ bool SampleBrowser::loadAllSamplesInFolder(bool detectPitch, int32_t* getNumSamp thisSample->partOfFolderBeingLoaded = false; #if ALPHA_OR_BETA_VERSION if (thisSample->numReasonsToBeLoaded <= 0) { - display->freezeWithError("E213"); // I put this here to try and catch an E004 Luc got + FREEZE_WITH_ERROR("E213"); // I put this here to try and catch an E004 Luc got } #endif thisSample->removeReason("E392"); // Remove that temporary reason we added @@ -1644,7 +1644,7 @@ bool SampleBrowser::importFolderAsMultisamples() { Sample* thisSample = sortArea[s]; #if ALPHA_OR_BETA_VERSION if (thisSample->numReasonsToBeLoaded <= 0) { - display->freezeWithError("E215"); // I put this here to try and catch an E004 Luc got + FREEZE_WITH_ERROR("E215"); // I put this here to try and catch an E004 Luc got } #endif thisSample->removeReason("E393"); // Remove that temporary reason we added above @@ -1760,7 +1760,7 @@ bool SampleBrowser::importFolderAsMultisamples() { else { #if ALPHA_OR_BETA_VERSION if (soundEditor.currentSource->ranges.elementSize != sizeof(MultisampleRange)) { - display->freezeWithError("E431"); + FREEZE_WITH_ERROR("E431"); } #endif range = (MultisampleRange*)soundEditor.currentSource->ranges.insertMultiRange( @@ -1787,7 +1787,7 @@ bool SampleBrowser::importFolderAsMultisamples() { } if (ALPHA_OR_BETA_VERSION && thisSample->numReasonsToBeLoaded <= 0) { - display->freezeWithError("E216"); // I put this here to try and catch an E004 Luc got + FREEZE_WITH_ERROR("E216"); // I put this here to try and catch an E004 Luc got } thisSample->removeReason("E394"); // Remove that temporary reason we added above @@ -1975,7 +1975,7 @@ bool SampleBrowser::importFolderAsKit() { #if ALPHA_OR_BETA_VERSION if (thisSample->numReasonsToBeLoaded <= 0) { - display->freezeWithError("E217"); // I put this here to try and catch an E004 Luc got + FREEZE_WITH_ERROR("E217"); // I put this here to try and catch an E004 Luc got } #endif thisSample->removeReason("E395"); diff --git a/src/deluge/gui/ui/load/load_song_ui.cpp b/src/deluge/gui/ui/load/load_song_ui.cpp index 0d507800a2..de99945847 100644 --- a/src/deluge/gui/ui/load/load_song_ui.cpp +++ b/src/deluge/gui/ui/load/load_song_ui.cpp @@ -127,7 +127,7 @@ bool LoadSongUI::opened() { indicator_leds::setLedState(IndicatorLED::SCALE_MODE, false); if (ALPHA_OR_BETA_VERSION && currentUIMode == UI_MODE_WAITING_FOR_NEXT_FILE_TO_LOAD) { - display->freezeWithError("E188"); + FREEZE_WITH_ERROR("E188"); } return true; diff --git a/src/deluge/gui/ui/menus.cpp b/src/deluge/gui/ui/menus.cpp index 2a9fab86f3..648695b7a3 100644 --- a/src/deluge/gui/ui/menus.cpp +++ b/src/deluge/gui/ui/menus.cpp @@ -27,8 +27,12 @@ #include "gui/menu_item/cv/volts.h" #include "gui/menu_item/decimal.h" #include "gui/menu_item/defaults/bend_range.h" +#include "gui/menu_item/defaults/grid_allow_green_selection.h" +#include "gui/menu_item/defaults/grid_default_active_mode.h" +#include "gui/menu_item/defaults/grid_unarm_empty_pads.h" #include "gui/menu_item/defaults/keyboard_layout.h" #include "gui/menu_item/defaults/magnitude.h" +#include "gui/menu_item/defaults/metronome_volume.h" #include "gui/menu_item/defaults/scale.h" #include "gui/menu_item/defaults/session_layout.h" #include "gui/menu_item/defaults/velocity.h" @@ -821,10 +825,21 @@ Submenu defaultUIKeyboard{ {&defaultKeyboardLayoutMenu}, }; +defaults::DefaultGridDefaultActiveMode defaultGridDefaultActiveMode{STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE, + STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ACTIVE_MODE}; +defaults::DefaultGridAllowGreenSelection defaultGridAllowGreenSelection{ + STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ALLOW_GREEN_SELECTION, STRING_FOR_DEFAULT_UI_DEFAULT_GRID_ALLOW_GREEN_SELECTION}; +defaults::DefaultGridUnarmEmptyPads defaultGridUnarmEmptyPads{STRING_FOR_DEFAULT_UI_DEFAULT_GRID_UNARM_EMPTY_PADS, + STRING_FOR_DEFAULT_UI_DEFAULT_GRID_UNARM_EMPTY_PADS}; +Submenu defaultSessionGridMenu{ + STRING_FOR_DEFAULT_UI_GRID, + {&defaultGridDefaultActiveMode, &defaultGridAllowGreenSelection, &defaultGridUnarmEmptyPads}, +}; + defaults::SessionLayout defaultSessionLayoutMenu{STRING_FOR_DEFAULT_UI_LAYOUT, STRING_FOR_DEFAULT_UI_LAYOUT}; Submenu defaultUISession{ STRING_FOR_DEFAULT_UI_SONG, - {&defaultSessionLayoutMenu}, + {&defaultSessionLayoutMenu, &defaultSessionGridMenu}, }; Submenu defaultUI{ @@ -839,6 +854,7 @@ defaults::Scale defaultScaleMenu{STRING_FOR_SCALE, STRING_FOR_DEFAULT_SCALE}; defaults::Velocity defaultVelocityMenu{STRING_FOR_VELOCITY, STRING_FOR_DEFAULT_VELOC_MENU_TITLE}; defaults::Magnitude defaultMagnitudeMenu{STRING_FOR_RESOLUTION, STRING_FOR_DEFAULT_RESOL_MENU_TITLE}; defaults::BendRange defaultBendRangeMenu{STRING_FOR_BEND_RANGE, STRING_FOR_DEFAULT_BEND_R}; +defaults::MetronomeVolume defaultMetronomeVolumeMenu{STRING_FOR_METRONOME, STRING_FOR_DEFAULT_METRO_MENU_TITLE}; Submenu defaultsSubmenu{ STRING_FOR_DEFAULTS, @@ -851,6 +867,7 @@ Submenu defaultsSubmenu{ &defaultVelocityMenu, &defaultMagnitudeMenu, &defaultBendRangeMenu, + &defaultMetronomeVolumeMenu, }, }; diff --git a/src/deluge/gui/ui/qwerty_ui.cpp b/src/deluge/gui/ui/qwerty_ui.cpp index 9c4cde4573..9d348d6da5 100644 --- a/src/deluge/gui/ui/qwerty_ui.cpp +++ b/src/deluge/gui/ui/qwerty_ui.cpp @@ -166,7 +166,7 @@ void QwertyUI::displayText(bool blinkImmediately) { memset(encodedAddition, 0, kNumericDisplayLength); if (totalTextLength == enteredTextEditPos || enteredText.get()[enteredTextEditPos] == ' ') { if (ALPHA_OR_BETA_VERSION && (editPosOnscreen < 0 || editPosOnscreen >= kNumericDisplayLength)) { - display->freezeWithError("E292"); + FREEZE_WITH_ERROR("E292"); } encodedAddition[editPosOnscreen] = 0x08; encodedEditPosAndAHalf = diff --git a/src/deluge/gui/ui/save/save_song_ui.cpp b/src/deluge/gui/ui/save/save_song_ui.cpp index 979afb3076..6b94170b1c 100644 --- a/src/deluge/gui/ui/save/save_song_ui.cpp +++ b/src/deluge/gui/ui/save/save_song_ui.cpp @@ -112,7 +112,7 @@ void SaveSongUI::focusRegained() { bool SaveSongUI::performSave(bool mayOverwrite) { if (ALPHA_OR_BETA_VERSION && currentlyAccessingCard) { - display->freezeWithError("E316"); + FREEZE_WITH_ERROR("E316"); } if (currentSong->hasAnyPendingNextOverdubs()) { diff --git a/src/deluge/gui/ui/slicer.cpp b/src/deluge/gui/ui/slicer.cpp index 1d0d597ecd..98b2441337 100644 --- a/src/deluge/gui/ui/slicer.cpp +++ b/src/deluge/gui/ui/slicer.cpp @@ -658,7 +658,7 @@ void Slicer::doSlice() { #if 1 || ALPHA_OR_BETA_VERSION if (!firstRange->sampleHolder.audioFile) { - display->freezeWithError("i032"); // Trying to narrow down E368 that Kevin F got + FREEZE_WITH_ERROR("i032"); // Trying to narrow down E368 that Kevin F got } #endif diff --git a/src/deluge/gui/ui/sound_editor.cpp b/src/deluge/gui/ui/sound_editor.cpp index ac31d6213f..be7c42dfde 100644 --- a/src/deluge/gui/ui/sound_editor.cpp +++ b/src/deluge/gui/ui/sound_editor.cpp @@ -650,6 +650,10 @@ ActionResult SoundEditor::horizontalEncoderAction(int32_t offset) { void SoundEditor::selectEncoderAction(int8_t offset) { + if (Buttons::isButtonPressed(deluge::hid::button::SHIFT)) { + offset = offset * 5; + } + if (currentUIMode != UI_MODE_NONE && currentUIMode != UI_MODE_AUDITIONING && currentUIMode != UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR) { return; diff --git a/src/deluge/gui/ui_timer_manager.h b/src/deluge/gui/ui_timer_manager.h index c6792296ec..09d27a884e 100644 --- a/src/deluge/gui/ui_timer_manager.h +++ b/src/deluge/gui/ui_timer_manager.h @@ -38,7 +38,8 @@ #define TIMER_OLED_CONSOLE 16 #define TIMER_OLED_SCROLLING_AND_BLINKING 17 #define TIMER_SYSEX_DISPLAY 18 -#define NUM_TIMERS 19 +#define TIMER_METER_INDICATOR_BLINK 19 +#define NUM_TIMERS 20 struct Timer { bool active; diff --git a/src/deluge/gui/views/arranger_view.cpp b/src/deluge/gui/views/arranger_view.cpp index 51d0d266df..f10d44054d 100644 --- a/src/deluge/gui/views/arranger_view.cpp +++ b/src/deluge/gui/views/arranger_view.cpp @@ -425,7 +425,6 @@ void ArrangerView::setLedStates() { } void ArrangerView::focusRegained() { - view.focusRegained(); repopulateOutputsOnScreen(false); @@ -649,7 +648,7 @@ void ArrangerView::beginAudition(Output* output) { if (noteRow) { drum = noteRow->drum; if (drum && drum->type == DrumType::SOUND && !noteRow->paramManager.containsAnyMainParamCollections()) { - display->freezeWithError("E324"); // Vinz got this! I may have since fixed. + FREEZE_WITH_ERROR("E324"); // Vinz got this! I may have since fixed. } } else { @@ -1177,7 +1176,7 @@ void ArrangerView::editPadAction(int32_t x, int32_t y, bool on) { int32_t squareEnd = getPosFromSquare(x + 1, xScroll); if (squareStart >= squareEnd) { - display->freezeWithError("E210"); + FREEZE_WITH_ERROR("E210"); } // No previous press @@ -1243,7 +1242,7 @@ void ArrangerView::editPadAction(int32_t x, int32_t y, bool on) { int32_t j = output->clipInstances.search(squareStart, GREATER_OR_EQUAL); ClipInstance* nextClipInstance = output->clipInstances.getElement(j); if (nextClipInstance && nextClipInstance->pos == squareStart) { - display->freezeWithError("E233"); // Yes, this happened to someone. Including me!! + FREEZE_WITH_ERROR("E233"); // Yes, this happened to someone. Including me!! } } @@ -1297,7 +1296,7 @@ void ArrangerView::editPadAction(int32_t x, int32_t y, bool on) { ClipInstance* nextInstance = output->clipInstances.getElement(pressedClipInstanceIndex + 1); if (nextInstance) { if (nextInstance->pos == squareStart) { - display->freezeWithError("E232"); + FREEZE_WITH_ERROR("E232"); } } } @@ -1318,21 +1317,21 @@ void ArrangerView::editPadAction(int32_t x, int32_t y, bool on) { } if (clipInstance->length < 1) { - display->freezeWithError("E049"); + FREEZE_WITH_ERROR("E049"); } ClipInstance* nextInstance = output->clipInstances.getElement(pressedClipInstanceIndex + 1); if (nextInstance) { if (nextInstance->pos == squareStart) { - display->freezeWithError("E209"); + FREEZE_WITH_ERROR("E209"); } int32_t maxLength = nextInstance->pos - squareStart; if (clipInstance->length > maxLength) { clipInstance->length = maxLength; if (clipInstance->length < 1) { - display->freezeWithError("E048"); + FREEZE_WITH_ERROR("E048"); } } } @@ -1340,7 +1339,7 @@ void ArrangerView::editPadAction(int32_t x, int32_t y, bool on) { if (clipInstance->length > kMaxSequenceLength - clipInstance->pos) { clipInstance->length = kMaxSequenceLength - clipInstance->pos; if (clipInstance->length < 1) { - display->freezeWithError("E045"); + FREEZE_WITH_ERROR("E045"); } } @@ -2454,7 +2453,7 @@ void ArrangerView::changeOutputToAudio() { if (instrumentClip) { int32_t clipIndex = currentSong->sessionClips.getIndexForClip(instrumentClip); if (ALPHA_OR_BETA_VERSION && clipIndex == -1) { - display->freezeWithError("E266"); + FREEZE_WITH_ERROR("E266"); } newClip = currentSong->replaceInstrumentClipWithAudioClip(instrumentClip, clipIndex); diff --git a/src/deluge/gui/views/automation_instrument_clip_view.cpp b/src/deluge/gui/views/automation_instrument_clip_view.cpp index e1b48be93d..a2c22f6b8f 100644 --- a/src/deluge/gui/views/automation_instrument_clip_view.cpp +++ b/src/deluge/gui/views/automation_instrument_clip_view.cpp @@ -810,21 +810,27 @@ DisplayParameterValue DisplayParameterName */ void AutomationInstrumentClipView::renderDisplay(int32_t knobPosLeft, int32_t knobPosRight, bool modEncoderAction) { + InstrumentClip* clip = getCurrentClip(); + Instrument* instrument = (Instrument*)clip->output; + + //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) { + knobPosLeft = calculateKnobPosForDisplay(clip, knobPosLeft); + knobPosRight = calculateKnobPosForDisplay(clip, knobPosRight); + } + //OLED Display if (display->haveOLED()) { - renderDisplayOLED(knobPosLeft, knobPosRight); + renderDisplayOLED(clip, instrument, knobPosLeft, knobPosRight); } //7SEG Display else { - renderDisplay7SEG(knobPosLeft, modEncoderAction); + renderDisplay7SEG(clip, instrument, knobPosLeft, modEncoderAction); } } -void AutomationInstrumentClipView::renderDisplayOLED(int32_t knobPosLeft, int32_t knobPosRight) { - - InstrumentClip* clip = getCurrentClip(); - Instrument* instrument = (Instrument*)clip->output; - +void AutomationInstrumentClipView::renderDisplayOLED(InstrumentClip* clip, Instrument* instrument, int32_t knobPosLeft, + int32_t knobPosRight) { deluge::hid::display::OLED::clearMainImage(); if (isOnAutomationOverview() || (instrument->type == InstrumentType::CV)) { @@ -852,7 +858,7 @@ void AutomationInstrumentClipView::renderDisplayOLED(int32_t knobPosLeft, int32_ else if (instrument->type != InstrumentType::CV) { //display parameter name char parameterName[30]; - getParameterName(parameterName); + getParameterName(clip, instrument, parameterName); #if OLED_MAIN_HEIGHT_PIXELS == 64 int32_t yPos = OLED_MAIN_TOPMOST_PIXEL + 12; @@ -917,11 +923,8 @@ void AutomationInstrumentClipView::renderDisplayOLED(int32_t knobPosLeft, int32_ deluge::hid::display::OLED::sendMainImage(); } -void AutomationInstrumentClipView::renderDisplay7SEG(int32_t knobPosLeft, bool modEncoderAction) { - - InstrumentClip* clip = getCurrentClip(); - Instrument* instrument = (Instrument*)clip->output; - +void AutomationInstrumentClipView::renderDisplay7SEG(InstrumentClip* clip, Instrument* instrument, int32_t knobPosLeft, + bool modEncoderAction) { //display OVERVIEW or CANT if (isOnAutomationOverview() || (instrument->type == InstrumentType::CV)) { if (instrument->type != InstrumentType::CV) { @@ -962,18 +965,14 @@ void AutomationInstrumentClipView::renderDisplay7SEG(int32_t knobPosLeft, bool m //display parameter name else { char parameterName[30]; - getParameterName(parameterName); + getParameterName(clip, instrument, parameterName); display->setScrollingText(parameterName); } } } //get's the name of the Parameter being edited so it can be displayed on the screen -void AutomationInstrumentClipView::getParameterName(char* parameterName) { - - InstrumentClip* clip = getCurrentClip(); - Instrument* instrument = (Instrument*)clip->output; - +void AutomationInstrumentClipView::getParameterName(InstrumentClip* clip, Instrument* instrument, char* parameterName) { if (instrument->type == InstrumentType::SYNTH || instrument->type == InstrumentType::KIT) { if (clip->lastSelectedParamKind == Param::Kind::PATCHED) { strncpy(parameterName, getPatchedParamDisplayName(clip->lastSelectedParamID), 29); @@ -1017,6 +1016,20 @@ void AutomationInstrumentClipView::getParameterName(char* parameterName) { } } +//for non-MIDI instruments, convert deluge internal knobPos range to same range as used by menu's. +int32_t AutomationInstrumentClipView::calculateKnobPosForDisplay(InstrumentClip* clip, int32_t knobPos) { + int32_t offset = 0; + + //if the parameter is pan, convert knobPos from 0 - 50 to -25 to +25 + if ((clip->lastSelectedParamID == Param::Local::PAN) + || (clip->lastSelectedParamID == Param::Unpatched::GlobalEffectable::PAN)) { + offset = kMaxMenuPanValue; + } + + //convert knobPos from 0 - 128 to 0 - 50 + return (((((knobPos << 20) / kMaxKnobPos) * kMaxMenuValue) >> 20) - offset); +} + //adjust the LED meters and update the display /*updated function for displaying automation when playback is enabled (called from ui_timer_manager). @@ -1450,8 +1463,10 @@ ActionResult AutomationInstrumentClipView::padAction(int32_t x, int32_t y, int32 //if the user wants to change the parameter they are editing using Shift + Pad shortcut if (velocity) { - if (Buttons::isShiftButtonPressed()) { - + if (Buttons::isShiftButtonPressed() + || (isUIModeActive(UI_MODE_AUDITIONING) + && (runtimeFeatureSettings.get(RuntimeFeatureSettingType::AutomationDisableAuditionPadShortcuts) + == RuntimeFeatureStateToggle::Off))) { initPadSelection(); handleSinglePadPress(modelStack, clip, x, y, true); @@ -2416,6 +2431,13 @@ bool AutomationInstrumentClipView::modEncoderActionForSelectedPad(int32_t whichM int32_t newKnobPos = calculateKnobPosForModEncoderTurn(knobPos, offset); + //ignore modEncoderTurn for Midi CC if current or new knobPos exceeds 127 + //if current knobPos exceeds 127, e.g. it's 128, then it needs to drop to 126 before a value change gets recorded + //if newKnobPos exceeds 127, then it means current knobPos was 127 and it was increased to 128. In which case, ignore value change + if ((clip->output->type == InstrumentType::MIDI_OUT) && (newKnobPos == 64)) { + return true; + } + //use default interpolation settings initInterpolation(); @@ -2454,6 +2476,13 @@ void AutomationInstrumentClipView::modEncoderActionForUnselectedPad(int32_t whic int32_t newKnobPos = calculateKnobPosForModEncoderTurn(knobPos, offset); + //ignore modEncoderTurn for Midi CC if current or new knobPos exceeds 127 + //if current knobPos exceeds 127, e.g. it's 128, then it needs to drop to 126 before a value change gets recorded + //if newKnobPos exceeds 127, then it means current knobPos was 127 and it was increased to 128. In which case, ignore value change + if ((clip->output->type == InstrumentType::MIDI_OUT) && (newKnobPos == 64)) { + return; + } + int32_t newValue = modelStackWithParam->paramCollection->knobPosToParamValue(newKnobPos, modelStackWithParam); @@ -2686,7 +2715,13 @@ void AutomationInstrumentClipView::selectEncoderAction(int8_t offset) { InstrumentClip* clip = getCurrentClip(); Instrument* instrument = (Instrument*)clip->output; - if (instrument->type == InstrumentType::SYNTH || instrument->type == InstrumentType::KIT) { + //if you've selected a mod encoder (e.g. by pressing modEncoderButton) and you're in Automation Overview + //the currentUIMode will change to Selecting Midi CC. In this case, turning select encoder should allow + //you to change the midi CC assignment to that modEncoder + if (currentUIMode == UI_MODE_SELECTING_MIDI_CC) { + InstrumentClipMinder::selectEncoderAction(offset); + } + else if (instrument->type == InstrumentType::SYNTH || instrument->type == InstrumentType::KIT) { //if you're a kit with affect entire enabled if (instrument->type == InstrumentType::KIT && instrumentClipView.getAffectEntire()) { @@ -3301,7 +3336,7 @@ void AutomationInstrumentClipView::handleSinglePadPress(ModelStackWithTimelineCo //use default interpolation settings initInterpolation(); - int32_t newKnobPos = calculateKnobPosForSinglePadPress(yDisplay); + int32_t newKnobPos = calculateKnobPosForSinglePadPress(instrument, yDisplay); setParameterAutomationValue(modelStackWithParam, newKnobPos, squareStart, xDisplay, effectiveLength); } } @@ -3311,7 +3346,7 @@ void AutomationInstrumentClipView::handleSinglePadPress(ModelStackWithTimelineCo } //calculates what the new parameter value is when you press a single pad -int32_t AutomationInstrumentClipView::calculateKnobPosForSinglePadPress(int32_t yDisplay) { +int32_t AutomationInstrumentClipView::calculateKnobPosForSinglePadPress(Instrument* instrument, int32_t yDisplay) { int32_t newKnobPos = 0; @@ -3321,7 +3356,13 @@ int32_t AutomationInstrumentClipView::calculateKnobPosForSinglePadPress(int32_t } //if you are pressing the top pad, set the value to max (128) else { - newKnobPos = kMaxKnobPos; + //for Midi Clips, maxKnobPos = 127 + if (instrument->type == InstrumentType::MIDI_OUT) { + newKnobPos = kMaxKnobPos - 1; //128 - 1 = 127 + } + else { + newKnobPos = kMaxKnobPos; + } } //in the deluge knob positions are stored in the range of -64 to + 64, so need to adjust newKnobPos set above. @@ -3361,8 +3402,8 @@ void AutomationInstrumentClipView::handleMultiPadPress(ModelStackWithTimelineCou //otherwise if it's a regular long press, calculate values from the y position of the pads pressed else { - firstPadValue = calculateKnobPosForSinglePadPress(firstPadY) + kKnobPosOffset; - secondPadValue = calculateKnobPosForSinglePadPress(secondPadY) + kKnobPosOffset; + firstPadValue = calculateKnobPosForSinglePadPress(instrument, firstPadY) + kKnobPosOffset; + secondPadValue = calculateKnobPosForSinglePadPress(instrument, secondPadY) + kKnobPosOffset; } //converting variables to float for more accurate interpolation calculation diff --git a/src/deluge/gui/views/automation_instrument_clip_view.h b/src/deluge/gui/views/automation_instrument_clip_view.h index accee9439f..d6bad3fa9b 100644 --- a/src/deluge/gui/views/automation_instrument_clip_view.h +++ b/src/deluge/gui/views/automation_instrument_clip_view.h @@ -62,8 +62,6 @@ class AutomationInstrumentClipView final : public ClipView, public InstrumentCli uint8_t occupancyMask[][kDisplayWidth + kSideBarWidth]); void renderDisplay(int32_t knobPosLeft = kNoSelection, int32_t knobPosRight = kNoSelection, bool modEncoderAction = false); - void renderDisplayOLED(int32_t knobPosLeft = kNoSelection, int32_t knobPosRight = kNoSelection); - void renderDisplay7SEG(int32_t knobPosLeft = kNoSelection, bool modEncoderAction = false); void displayAutomation(bool padSelected = false, bool updateDisplay = true); void renderOLED(uint8_t image[][OLED_MAIN_WIDTH_PIXELS]) { InstrumentClipMinder::renderOLED(image); } @@ -129,6 +127,10 @@ class AutomationInstrumentClipView final : public ClipView, public InstrumentCli void renderRow(ModelStackWithTimelineCounter* modelStack, ModelStackWithAutoParam* modelStackWithParam, uint8_t* image, uint8_t occupancyMask[], int32_t yDisplay = 0, bool isAutomated = false); void renderLove(uint8_t* image, uint8_t occupancyMask[], int32_t yDisplay = 0); + void renderDisplayOLED(InstrumentClip* clip, Instrument* instrument, int32_t knobPosLeft = kNoSelection, + int32_t knobPosRight = kNoSelection); + void renderDisplay7SEG(InstrumentClip* clip, Instrument* instrument, int32_t knobPosLeft = kNoSelection, + bool modEncoderAction = false); //Enter/Exit Scale Mode void enterScaleMode(uint8_t yDisplay = 255); @@ -151,7 +153,7 @@ class AutomationInstrumentClipView final : public ClipView, public InstrumentCli int32_t getEffectiveLength(ModelStackWithTimelineCounter* modelStack); uint32_t getMiddlePosFromSquare(ModelStackWithTimelineCounter* modelStack, int32_t xDisplay); - void getParameterName(char* parameterName); + void getParameterName(InstrumentClip* clip, Instrument* instrument, char* parameterName); int32_t getParameterKnobPos(ModelStackWithAutoParam* modelStack, uint32_t pos); bool getNodeInterpolation(ModelStackWithAutoParam* modelStack, int32_t pos, bool reversed); @@ -164,7 +166,7 @@ class AutomationInstrumentClipView final : public ClipView, public InstrumentCli bool recordSinglePadPress(int32_t xDisplay, int32_t yDisplay); void handleSinglePadPress(ModelStackWithTimelineCounter* modelStack, InstrumentClip* clip, int32_t xDisplay, int32_t yDisplay, bool shortcutPress = false); - int32_t calculateKnobPosForSinglePadPress(int32_t yDisplay); + int32_t calculateKnobPosForSinglePadPress(Instrument* instrument, int32_t yDisplay); void handleMultiPadPress(ModelStackWithTimelineCounter* modelStack, InstrumentClip* clip, int32_t firstPadX, int32_t firstPadY, int32_t secondPadX, int32_t secondPadY, bool modEncoderAction = false); @@ -172,6 +174,7 @@ class AutomationInstrumentClipView final : public ClipView, public InstrumentCli int32_t xDisplay = kNoSelection, bool modEncoderAction = false); int32_t calculateKnobPosForModEncoderTurn(int32_t knobPos, int32_t offset); + int32_t calculateKnobPosForDisplay(InstrumentClip* clip, int32_t knobPos); void displayCVErrorMessage(); void resetShortcutBlinking(); diff --git a/src/deluge/gui/views/instrument_clip_view.cpp b/src/deluge/gui/views/instrument_clip_view.cpp index 243716a628..c489cedda1 100644 --- a/src/deluge/gui/views/instrument_clip_view.cpp +++ b/src/deluge/gui/views/instrument_clip_view.cpp @@ -519,7 +519,7 @@ ActionResult InstrumentClipView::buttonAction(deluge::hid::Button b, bool on, bo if (ALPHA_OR_BETA_VERSION && (noteRowIndex < 0 || noteRowIndex >= clip->noteRows.getNumElements())) { - display->freezeWithError("E323"); + FREEZE_WITH_ERROR("E323"); } if (clip->isActiveOnOutput()) { @@ -2750,7 +2750,7 @@ void InstrumentClipView::sendAuditionNote(bool on, uint8_t yDisplay, uint8_t vel if (on) { if (drum->type == DrumType::SOUND && !modelStackWithNoteRow->getNoteRow()->paramManager.containsAnyMainParamCollections()) { - display->freezeWithError("E325"); // Trying to catch an E313 that Vinz got + FREEZE_WITH_ERROR("E325"); // Trying to catch an E313 that Vinz got } ((Kit*)instrument)->beginAuditioningforDrum(modelStackWithNoteRow, drum, velocity, zeroMPEValues); } @@ -5184,7 +5184,7 @@ void InstrumentClipView::modEncoderAction(int32_t whichModEncoder, int32_t offse if (kit->selectedDrum && kit->selectedDrum->type != DrumType::SOUND) { if (ALPHA_OR_BETA_VERSION && !kit->activeClip) { - display->freezeWithError("E381"); + FREEZE_WITH_ERROR("E381"); } ModelStackWithTimelineCounter* modelStackWithTimelineCounter = diff --git a/src/deluge/gui/views/session_view.cpp b/src/deluge/gui/views/session_view.cpp index 544470777a..ecfe7149d7 100644 --- a/src/deluge/gui/views/session_view.cpp +++ b/src/deluge/gui/views/session_view.cpp @@ -1921,9 +1921,8 @@ void SessionView::graphicsRoutine() { counter = (counter + 1) % 5; if (counter == 0) { uint8_t gr = AudioEngine::mastercompressor.gainReduction; - //uint8_t mv = int(6 * AudioEngine::mastercompressor.meanVolume); - indicator_leds::setKnobIndicatorLevel(1, gr); //Gain Reduction LED - //indicator_leds::setKnobIndicatorLevel(0, mv); //Input level LED + + indicator_leds::setMeterLevel(1, gr); //Gain Reduction LED } } } @@ -2667,6 +2666,7 @@ Clip* SessionView::getClipForLayout() { } void SessionView::selectLayout(int8_t offset) { + gridSetDefaultMode(); gridResetPresses(); gridModeActive = gridModeSelected; @@ -3215,8 +3215,13 @@ ActionResult SessionView::gridHandlePads(int32_t x, int32_t y, int32_t on) { } } else { - if (!gridActiveModeUsed) { - gridModeSelected = gridModeActive; + if (FlashStorage::defaultGridActiveMode == GridDefaultActiveModeSelection) { + if (!gridActiveModeUsed) { + gridModeSelected = gridModeActive; + } + } + else { + gridSetDefaultMode(); } gridModeActive = gridModeSelected; @@ -3413,6 +3418,24 @@ ActionResult SessionView::gridHandlePadsLaunch(int32_t x, int32_t y, int32_t on, } if (clip == nullptr) { + if (on && currentUIMode == UI_MODE_NONE && FlashStorage::gridUnarmEmptyPads) { + auto maxTrack = gridTrackCount(); + Output* track = gridTrackFromX(x, maxTrack); + if (track != nullptr) { + for (int32_t idxClip = 0; idxClip < currentSong->sessionClips.getNumElements(); ++idxClip) { + Clip* sessionClip = currentSong->sessionClips.getClipAtIndex(idxClip); + if (sessionClip->output == track) { + if (sessionClip->activeIfNoSolo) { + gridToggleClipPlay(sessionClip, Buttons::isShiftButtonPressed()); + } + else { + sessionClip->armState = ArmState::OFF; + } + } + } + } + } + return ActionResult::DEALT_WITH; } @@ -3422,13 +3445,77 @@ ActionResult SessionView::gridHandlePadsLaunch(int32_t x, int32_t y, int32_t on, return ActionResult::ACTIONED_AND_CAUSED_CHANGE; } + if (FlashStorage::gridAllowGreenSelection) { + return gridHandlePadsLaunchWithSelection(x, y, on, clip); + } + else { + return gridHandlePadsLaunchImmediate(x, y, on, clip); + } +} + +ActionResult SessionView::gridHandlePadsLaunchImmediate(int32_t x, int32_t y, int32_t on, Clip* clip) { // From here all actions only happen on press if (!on) { return ActionResult::DEALT_WITH; } - // Normal arming, handle cases normally in View::clipStatusPadAction - if (!Buttons::isShiftButtonPressed()) { + gridHandlePadsLaunchToggleArming(clip, Buttons::isShiftButtonPressed()); + + return ActionResult::ACTIONED_AND_CAUSED_CHANGE; +} + +ActionResult SessionView::gridHandlePadsLaunchWithSelection(int32_t x, int32_t y, int32_t on, Clip* clip) { + if (on) { + // Immediate arming, immediate consumption + if (Buttons::isShiftButtonPressed()) { + gridHandlePadsLaunchToggleArming(clip, true); + return ActionResult::ACTIONED_AND_CAUSED_CHANGE; + } + + if (gridFirstPressedX == -1 && gridFirstPressedY == -1) { + gridFirstPressedX = x; + gridFirstPressedY = y; + + // Allow clip control (selection) + currentUIMode = UI_MODE_CLIP_PRESSED_IN_SONG_VIEW; + performActionOnPadRelease = true; + selectedClipTimePressed = AudioEngine::audioSampleTimer; + view.setActiveModControllableTimelineCounter(clip); + view.displayOutputName(clip->output, true, clip); + if (display->haveOLED()) { + deluge::hid::display::OLED::sendMainImage(); + } + } + // Special case, if there are already selected pads we allow immediate arming all others + else { + return gridHandlePadsLaunchImmediate(x, y, on, clip); + } + } + else { + if (gridFirstPressedX == x && gridFirstPressedY == y) { + if (isUIModeActive(UI_MODE_CLIP_PRESSED_IN_SONG_VIEW) && performActionOnPadRelease + && AudioEngine::audioSampleTimer - selectedClipTimePressed < kShortPressTime) { + + gridHandlePadsLaunchToggleArming(clip, false); + } + + clipPressEnded(); + } + } + + return ActionResult::ACTIONED_AND_CAUSED_CHANGE; +} + +void SessionView::gridHandlePadsLaunchToggleArming(Clip* clip, bool immediate) { + if (immediate) { + if (currentUIMode == UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON) { + session.soloClipAction(clip, kInternalButtonPressLatency); + } + else { + gridToggleClipPlay(clip, true); + } + } + else { if (currentUIMode == UI_MODE_VIEWING_RECORD_ARMING) { // Here I removed the overdubbing settings clip->armedForRecording = !clip->armedForRecording; @@ -3447,17 +3534,6 @@ ActionResult SessionView::gridHandlePadsLaunch(int32_t x, int32_t y, int32_t on, // Make sure we can mute additional pads after this and don't loose UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON } } - // Immediate arming, immediate consumption - else { - if (currentUIMode == UI_MODE_HOLDING_HORIZONTAL_ENCODER_BUTTON) { - session.soloClipAction(clip, kInternalButtonPressLatency); - } - else { - gridToggleClipPlay(clip, true); - } - } - - return ActionResult::ACTIONED_AND_CAUSED_CHANGE; } ActionResult SessionView::gridHandleScroll(int32_t offsetX, int32_t offsetY) { diff --git a/src/deluge/gui/views/session_view.h b/src/deluge/gui/views/session_view.h index 1f07a03a4f..a95f9842cb 100644 --- a/src/deluge/gui/views/session_view.h +++ b/src/deluge/gui/views/session_view.h @@ -20,6 +20,7 @@ #include "definitions_cxx.hpp" #include "gui/views/clip_navigation_timeline_view.h" #include "hid/button.h" +#include "storage/flash_storage.h" class Editor; class InstrumentClip; @@ -141,6 +142,9 @@ class SessionView final : public ClipNavigationTimelineView { ActionResult gridHandlePads(int32_t x, int32_t y, int32_t on); ActionResult gridHandlePadsEdit(int32_t x, int32_t y, int32_t on, Clip* clip); ActionResult gridHandlePadsLaunch(int32_t x, int32_t y, int32_t on, Clip* clip); + ActionResult gridHandlePadsLaunchImmediate(int32_t x, int32_t y, int32_t on, Clip* clip); + ActionResult gridHandlePadsLaunchWithSelection(int32_t x, int32_t y, int32_t on, Clip* clip); + void gridHandlePadsLaunchToggleArming(Clip* clip, bool immediate); ActionResult gridHandleScroll(int32_t offsetX, int32_t offsetY); @@ -191,6 +195,19 @@ class SessionView final : public ClipNavigationTimelineView { int32_t gridTrackIndexFromX(uint32_t x, uint32_t maxTrack); Output* gridTrackFromX(uint32_t x, uint32_t maxTrack); Clip* gridClipFromCoords(uint32_t x, uint32_t y); + + inline void gridSetDefaultMode() { + switch (FlashStorage::defaultGridActiveMode) { + case GridDefaultActiveModeGreen: { + gridModeSelected = SessionGridModeLaunch; + break; + } + case GridDefaultActiveModeBlue: { + gridModeSelected = SessionGridModeEdit; + break; + } + } + } }; extern SessionView sessionView; diff --git a/src/deluge/gui/views/view.cpp b/src/deluge/gui/views/view.cpp index 1fd37a6885..bb6e605c4e 100644 --- a/src/deluge/gui/views/view.cpp +++ b/src/deluge/gui/views/view.cpp @@ -859,26 +859,93 @@ void View::modEncoderAction(int32_t whichModEncoder, int32_t offset) { // Or, if normal case - an actual param else { + char modelStackTempMemory[MODEL_STACK_MAX_SIZE]; + copyModelStack(modelStackTempMemory, modelStackWithParam, sizeof(ModelStackWithThreeMainThings)); + ModelStackWithThreeMainThings* tempModelStack = (ModelStackWithThreeMainThings*)modelStackTempMemory; - char newModelStackMemory[MODEL_STACK_MAX_SIZE]; - - // Hack to make it so stutter can't be automated - if (modelStackWithParam->timelineCounterIsSet() - && !modelStackWithParam->paramCollection->doesParamIdAllowAutomation(modelStackWithParam)) { - copyModelStack(newModelStackMemory, modelStackWithParam, sizeof(ModelStackWithAutoParam)); - modelStackWithParam = (ModelStackWithAutoParam*)newModelStackMemory; - modelStackWithParam->setTimelineCounter(NULL); - } + InstrumentClip* clip = (InstrumentClip*)tempModelStack->getTimelineCounter(); int32_t value = modelStackWithParam->autoParam->getValuePossiblyAtPos(modPos, modelStackWithParam); int32_t knobPos = modelStackWithParam->paramCollection->paramValueToKnobPos(value, modelStackWithParam); int32_t lowerLimit = std::min(-64_i32, knobPos); int32_t newKnobPos = knobPos + offset; newKnobPos = std::clamp(newKnobPos, lowerLimit, 64_i32); + //ignore modEncoderTurn for Midi CC if current or new knobPos exceeds 127 + //if current knobPos exceeds 127, e.g. it's 128, then it needs to drop to 126 before a value change gets recorded + //if newKnobPos exceeds 127, then it means current knobPos was 127 and it was increased to 128. In which case, ignore value change + if ((getRootUI() == &instrumentClipView) || (getRootUI() == &automationInstrumentClipView)) { + if ((clip->output->type == InstrumentType::MIDI_OUT) && (newKnobPos == 64)) { + return; + } + } + + //don't display pop-up while in soundEditor as values are displayed on the menu screen + //unless you're turning a mod encoder for a different param than the menu displayed + if (((getCurrentUI() != &soundEditor) + || ((getCurrentUI() == &soundEditor) + && (soundEditor.getCurrentMenuItem()->getPatchedParamIndex() != modelStackWithParam->paramId))) + && !(modelStackWithParam->paramId == Param::Unpatched::STUTTER_RATE + && (runtimeFeatureSettings.get(RuntimeFeatureSettingType::QuantizedStutterRate) + == RuntimeFeatureStateToggle::On) + && !isUIModeActive(UI_MODE_STUTTERING))) { + + char buffer[5]; + int32_t valueForDisplay; + if (clip->output->type == InstrumentType::MIDI_OUT) { + valueForDisplay = newKnobPos + kKnobPosOffset; + } + else if ((modelStackWithParam->paramId == Param::Local::PAN) + || (modelStackWithParam->paramId == Param::Unpatched::GlobalEffectable::PAN)) { + valueForDisplay = + ((((newKnobPos << 20) / (kMaxKnobPos - kKnobPosOffset)) * kMaxMenuPanValue) >> 20); + } + else { + valueForDisplay = + (((((newKnobPos + kKnobPosOffset) << 20) / kMaxKnobPos) * kMaxMenuValue) >> 20); + } + intToString(valueForDisplay, buffer); + display->displayPopup(buffer); + } + + //if turning stutter mod encoder and stutter quantize is enabled + //display stutter quantization instead of knob position + if (modelStackWithParam->paramId == Param::Unpatched::STUTTER_RATE + && (runtimeFeatureSettings.get(RuntimeFeatureSettingType::QuantizedStutterRate) + == RuntimeFeatureStateToggle::On) + && !isUIModeActive(UI_MODE_STUTTERING)) { + char buffer[10]; + if (newKnobPos < -39) { // 4ths stutter: no leds turned on + strncpy(buffer, "4ths", 10); + } + else if (newKnobPos < -14) { // 8ths stutter: 1 led turned on + strncpy(buffer, "8ths", 10); + } + else if (newKnobPos < 14) { // 16ths stutter: 2 leds turned on + strncpy(buffer, "16ths", 10); + } + else if (newKnobPos < 39) { // 32nds stutter: 3 leds turned on + strncpy(buffer, "32nds", 10); + } + else { // 64ths stutter: all 4 leds turned on + strncpy(buffer, "64ths", 10); + } + display->displayPopup(buffer); + } + if (newKnobPos == knobPos) { return; } + char newModelStackMemory[MODEL_STACK_MAX_SIZE]; + + // Hack to make it so stutter can't be automated + if (modelStackWithParam->timelineCounterIsSet() + && !modelStackWithParam->paramCollection->doesParamIdAllowAutomation(modelStackWithParam)) { + copyModelStack(newModelStackMemory, modelStackWithParam, sizeof(ModelStackWithAutoParam)); + modelStackWithParam = (ModelStackWithAutoParam*)newModelStackMemory; + modelStackWithParam->setTimelineCounter(NULL); + } + int32_t newValue = modelStackWithParam->paramCollection->knobPosToParamValue(newKnobPos, modelStackWithParam); @@ -887,11 +954,6 @@ void View::modEncoderAction(int32_t whichModEncoder, int32_t offset) { modLength); if (activeModControllableModelStack.timelineCounterIsSet()) { - char modelStackTempMemory[MODEL_STACK_MAX_SIZE]; - copyModelStack(modelStackTempMemory, modelStackWithParam, sizeof(ModelStackWithThreeMainThings)); - ModelStackWithThreeMainThings* tempModelStack = - (ModelStackWithThreeMainThings*)modelStackTempMemory; - bool noteTailsAllowedAfter = modelStackWithParam->modControllable->allowNoteTails(tempModelStack->addSoundFlags()); @@ -1798,14 +1860,14 @@ void View::navigateThroughPresetsForInstrumentClip(int32_t offset, ModelStackWit kit, soundDrum)) { // If no ParamManager with a NoteRow somewhere... if (results.loadedFromFile) { - display->freezeWithError("E103"); + FREEZE_WITH_ERROR("E103"); } else if (instrumentAlreadyInSong) { - display->freezeWithError("E104"); + FREEZE_WITH_ERROR("E104"); } else { // Sven got - very rare! This means Kit was hibernating, I guess. - display->freezeWithError("E105"); + FREEZE_WITH_ERROR("E105"); } } } diff --git a/src/deluge/gui/waveform/waveform_renderer.cpp b/src/deluge/gui/waveform/waveform_renderer.cpp index f8933a7a43..852137493a 100644 --- a/src/deluge/gui/waveform/waveform_renderer.cpp +++ b/src/deluge/gui/waveform/waveform_renderer.cpp @@ -394,7 +394,7 @@ bool WaveformRenderer::findPeaksPerCol(Sample* sample, int64_t xScrollSamples, u SampleCluster* sampleCluster = sample->clusters.getElement(clusterIndexToDo); if (sampleCluster->cluster && sampleCluster->cluster->numReasonsToBeLoaded < 0) { - display->freezeWithError("E449"); // Trying to catch errer before i028, which users have gotten. + FREEZE_WITH_ERROR("E449"); // Trying to catch errer before i028, which users have gotten. } // If we're wanting to investigate the whole length of one Cluster, and that's already actually been done previously, we can just reuse those findings! @@ -429,8 +429,8 @@ bool WaveformRenderer::findPeaksPerCol(Sample* sample, int64_t xScrollSamples, u } if (cluster->numReasonsToBeLoaded <= 0) { - display->freezeWithError( - errorCode); // Branko V got this. Trying to catch E340 below, which Ron R got while recording + // Branko V got this. Trying to catch E340 below, which Ron R got while recording + FREEZE_WITH_ERROR(errorCode); } uint32_t numBytesToRead = endByteWithinCluster - startByteWithinCluster; @@ -445,12 +445,12 @@ bool WaveformRenderer::findPeaksPerCol(Sample* sample, int64_t xScrollSamples, u endByteWithinCluster += overshoot; SampleCluster* nextSampleCluster = sample->clusters.getElement(clusterIndexToDo + 1); if (nextSampleCluster->cluster && nextSampleCluster->cluster->numReasonsToBeLoaded < 0) { - display->freezeWithError("E450"); // Trying to catch errer before i028, which users have gotten. + FREEZE_WITH_ERROR("E450"); // Trying to catch errer before i028, which users have gotten. } nextCluster = nextSampleCluster->getCluster(sample, clusterIndexToDo, CLUSTER_LOAD_IMMEDIATELY); if (cluster->numReasonsToBeLoaded <= 0) { - display->freezeWithError("E342"); // Trying to catch E340 below, which Ron R got while recording + FREEZE_WITH_ERROR("E342"); // Trying to catch E340 below, which Ron R got while recording } if (!nextCluster) { diff --git a/src/deluge/hid/buttons.cpp b/src/deluge/hid/buttons.cpp index af1ac5e752..441afed46b 100644 --- a/src/deluge/hid/buttons.cpp +++ b/src/deluge/hid/buttons.cpp @@ -158,7 +158,8 @@ ActionResult buttonAction(deluge::hid::Button b, bool on, bool inCardRoutine) { delta += releaseTime; } // We got a short press, maybe enable sticky keys - if (delta < kShortPressTime) { + //5th of a second + if (delta < kSampleRate / 5) { // unstick shift if another button was pressed while shift was held, or we were already stuck and // this short press is to get us unstuck. shiftCurrentlyStuck = considerShiftReleaseForSticky && !shiftCurrentlyStuck; diff --git a/src/deluge/hid/display/display.cpp b/src/deluge/hid/display/display.cpp index daa401d924..2a316cd937 100644 --- a/src/deluge/hid/display/display.cpp +++ b/src/deluge/hid/display/display.cpp @@ -80,9 +80,7 @@ std::string_view getErrorMessage(int32_t error) { } // namespace deluge::hid::display extern "C" void freezeWithError(char const* error) { - if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError(error); - } + display->freezeWithError(error); } extern "C" void displayPopup(char const* text) { diff --git a/src/deluge/hid/display/oled.cpp b/src/deluge/hid/display/oled.cpp index d89841fb33..11f0ae8f4c 100644 --- a/src/deluge/hid/display/oled.cpp +++ b/src/deluge/hid/display/oled.cpp @@ -1231,12 +1231,12 @@ void OLED::freezeWithError(char const* text) { // Wait for existing DMA transfer to finish uint16_t startTime = *TCNT[TIMER_SYSTEM_SLOW]; while (!(DMACn(OLED_SPI_DMA_CHANNEL).CHSTAT_n & DMAC0_CHSTAT_n_TC) - && (uint16_t)(*TCNT[TIMER_SYSTEM_SLOW] - startTime) < msToSlowTimerCount(10)) {} + && (uint16_t)(*TCNT[TIMER_SYSTEM_SLOW] - startTime) < msToSlowTimerCount(50)) {} // Wait for PIC to de-select OLED, if it's been doing that. if (oledWaitingForMessage != 256) { startTime = *TCNT[TIMER_SYSTEM_SLOW]; - while ((uint16_t)(*TCNT[TIMER_SYSTEM_SLOW] - startTime) < msToSlowTimerCount(10)) { + while ((uint16_t)(*TCNT[TIMER_SYSTEM_SLOW] - startTime) < msToSlowTimerCount(50)) { uint8_t value; bool anything = uartGetChar(UART_ITEM_PIC, (char*)&value); if (anything && value == oledWaitingForMessage) { @@ -1254,7 +1254,7 @@ void OLED::freezeWithError(char const* text) { // Wait for selection to be done startTime = *TCNT[TIMER_SYSTEM_SLOW]; - while ((uint16_t)(*TCNT[TIMER_SYSTEM_SLOW] - startTime) < msToSlowTimerCount(10)) { + while ((uint16_t)(*TCNT[TIMER_SYSTEM_SLOW] - startTime) < msToSlowTimerCount(50)) { uint8_t value; bool anything = uartGetChar(UART_ITEM_PIC, (char*)&value); if (anything && value == 248) { diff --git a/src/deluge/hid/led/indicator_leds.cpp b/src/deluge/hid/led/indicator_leds.cpp index a295c64d3d..3546dabf43 100644 --- a/src/deluge/hid/led/indicator_leds.cpp +++ b/src/deluge/hid/led/indicator_leds.cpp @@ -39,6 +39,8 @@ uint8_t whichLevelIndicatorBlinking; bool levelIndicatorBlinkOn; uint8_t levelIndicatorBlinksLeft; +uint8_t whichKnobMetering; + void setLedState(LED led, bool newState, bool allowContinuedBlinking) { if (!allowContinuedBlinking) { @@ -164,8 +166,25 @@ void indicateAlertOnLed(LED led) { blinkLed(led, 3, 1); } +//this sets the level only if there hasn't been a value update in 500ms +void setMeterLevel(uint8_t whichKnob, uint8_t level) { + whichKnobMetering = whichKnob; + if (!uiTimerManager.isTimerSet(TIMER_METER_INDICATOR_BLINK)) { + actuallySetKnobIndicatorLevel(whichKnob, level); + } +} + // Level is out of 128 +//Set level and block metering for 500ms void setKnobIndicatorLevel(uint8_t whichKnob, uint8_t level) { + if (whichKnob == whichKnobMetering) { + uiTimerManager.setTimer(TIMER_METER_INDICATOR_BLINK, 500); + } + actuallySetKnobIndicatorLevel(whichKnob, level); +} + +//Just set level +void actuallySetKnobIndicatorLevel(uint8_t whichKnob, uint8_t level) { // If this indicator was blinking, stop it if (uiTimerManager.isTimerSet(TIMER_LEVEL_INDICATOR_BLINK) && whichLevelIndicatorBlinking == whichKnob) { uiTimerManager.unsetTimer(TIMER_LEVEL_INDICATOR_BLINK); diff --git a/src/deluge/hid/led/indicator_leds.h b/src/deluge/hid/led/indicator_leds.h index 5ccb4887b1..e4503b017f 100644 --- a/src/deluge/hid/led/indicator_leds.h +++ b/src/deluge/hid/led/indicator_leds.h @@ -82,7 +82,9 @@ void setLedState(LED led, bool newState, bool allowContinuedBlinking = false); void blinkLed(LED led, uint8_t numBlinks = 255, uint8_t blinkingType = 0, bool initialState = true); void ledBlinkTimeout(uint8_t blinkingType, bool forceRestart = false, bool resetToState = true); void indicateAlertOnLed(LED led); +void setMeterLevel(uint8_t whichKnob, uint8_t level); void setKnobIndicatorLevel(uint8_t whichKnob, uint8_t level); +void actuallySetKnobIndicatorLevel(uint8_t whichKnob, uint8_t level); void clearKnobIndicatorLevels(); void blinkKnobIndicator(int32_t whichKnob); void stopBlinkingKnobIndicator(int32_t whichKnob); diff --git a/src/deluge/hid/led/pad_leds.cpp b/src/deluge/hid/led/pad_leds.cpp index 7e07a8aba8..9908975ed0 100644 --- a/src/deluge/hid/led/pad_leds.cpp +++ b/src/deluge/hid/led/pad_leds.cpp @@ -438,7 +438,7 @@ void setupAudioClipCollapseOrExplodeAnimation(AudioClip* clip) { Sample* sample = (Sample*)clip->sampleHolder.audioFile; if (ALPHA_OR_BETA_VERSION && !sample) { - display->freezeWithError("E311"); + FREEZE_WITH_ERROR("E311"); } sampleMaxPeakFromZero = sample->getMaxPeakFromZero(); diff --git a/src/deluge/io/midi/midi_device_manager.cpp b/src/deluge/io/midi/midi_device_manager.cpp index 96663d771e..c92bf965e0 100644 --- a/src/deluge/io/midi/midi_device_manager.cpp +++ b/src/deluge/io/midi/midi_device_manager.cpp @@ -153,7 +153,7 @@ MIDIDeviceUSBHosted* getOrCreateHostedMIDIDeviceFromDetails(String* name, uint16 int32_t error = hostedMIDIDevices.insertElement(device, i); // We made sure, above, that there's space #if ALPHA_OR_BETA_VERSION if (error) { - display->freezeWithError("E405"); + FREEZE_WITH_ERROR("E405"); } #endif @@ -240,7 +240,7 @@ extern "C" void hostedDeviceDetached(int32_t ip, int32_t midiDeviceNum) { #if ALPHA_OR_BETA_VERSION if (midiDeviceNum == MAX_NUM_USB_MIDI_DEVICES) { - display->freezeWithError("E367"); + FREEZE_WITH_ERROR("E367"); } #endif diff --git a/src/deluge/io/midi/midi_engine.cpp b/src/deluge/io/midi/midi_engine.cpp index a5dd92a233..a7528fe790 100644 --- a/src/deluge/io/midi/midi_engine.cpp +++ b/src/deluge/io/midi/midi_engine.cpp @@ -954,7 +954,7 @@ void MidiEngine::midiMessageReceived(MIDIDevice* fromDevice, uint8_t statusType, &shouldDoMidiThruNow); #if MISSING_MESSAGE_CHECK if (lastWasNoteOn == (bool)(statusType & 1)) - display->freezeWithError("MISSED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + FREEZE_WITH_ERROR("MISSED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); lastWasNoteOn = statusType & 1; #endif break; diff --git a/src/deluge/memory/cache_manager.cpp b/src/deluge/memory/cache_manager.cpp index aff20dfe15..8380c85718 100644 --- a/src/deluge/memory/cache_manager.cpp +++ b/src/deluge/memory/cache_manager.cpp @@ -48,6 +48,7 @@ uint32_t CacheManager::ReclaimMemory(MemoryRegion& region, int32_t totalSizeNeed stealable = static_cast(reclamation_queue_[q].getFirst()); while (stealable != nullptr) { // If we've already looked at this one as part of a bigger run, move on + //this works because the uint cast makes negatives high numbers instead uint32_t lastTraversalQueue = stealable->lastTraversalNo - traversalNumberBeforeQueues; if (lastTraversalQueue <= q) { @@ -61,6 +62,7 @@ uint32_t CacheManager::ReclaimMemory(MemoryRegion& region, int32_t totalSizeNeed } // If we're forbidden from stealing from a particular thing (usually SampleCache), then make sure we don't + // TODO: this should never happen if (!stealable->mayBeStolen(thingNotToStealFrom)) { numRefusedTheft++; @@ -113,6 +115,8 @@ uint32_t CacheManager::ReclaimMemory(MemoryRegion& region, int32_t totalSizeNeed // If that one Stealable alone was big enough, that's great if (amountToExtend <= 0) { + //need to reset this since it's getting stolen + longestRunSeenInThisQueue = 0xFFFFFFFF; found = true; break; } @@ -136,6 +140,10 @@ uint32_t CacheManager::ReclaimMemory(MemoryRegion& region, int32_t totalSizeNeed stealable = static_cast(reclamation_queue_[q].getNext(stealable)); continue; } + else { + //reset this since it's getting stolen + longestRunSeenInThisQueue = 0xFFFFFFFF; + } newSpaceAddress = result.address; @@ -146,8 +154,10 @@ uint32_t CacheManager::ReclaimMemory(MemoryRegion& region, int32_t totalSizeNeed break; } - // End of that particular queue - so go to the next one longest_runs_[q] = longestRunSeenInThisQueue; + + // End of that particular queue - so go to the next one + currentTraversalNo++; } diff --git a/src/deluge/memory/general_memory_allocator.cpp b/src/deluge/memory/general_memory_allocator.cpp index af9111687f..cc1a38c879 100644 --- a/src/deluge/memory/general_memory_allocator.cpp +++ b/src/deluge/memory/general_memory_allocator.cpp @@ -68,7 +68,7 @@ void GeneralMemoryAllocator::checkStack(char const* caller) { Debug::println(caller); if (distance < 200) { - display->freezeWithError("E338"); + FREEZE_WITH_ERROR("E338"); Debug::println("COLLISION"); } } @@ -99,7 +99,7 @@ void* GeneralMemoryAllocator::allocExternal(uint32_t requiredSize) { void* address = regions[MEMORY_REGION_EXTERNAL].alloc(requiredSize, false, NULL); lock = false; if (!address) { - //numericDriver.freezeWithError("M998"); + //FREEZE_WITH_ERROR("M998"); return nullptr; } return address; @@ -190,7 +190,7 @@ int32_t GeneralMemoryAllocator::getRegion(void* address) { return MEMORY_REGION_EXTERNAL; } - display->freezeWithError("E339"); + FREEZE_WITH_ERROR("E339"); return 0; } diff --git a/src/deluge/memory/memory_region.cpp b/src/deluge/memory/memory_region.cpp index 681197e82e..2f6bb36b6a 100644 --- a/src/deluge/memory/memory_region.cpp +++ b/src/deluge/memory/memory_region.cpp @@ -83,7 +83,7 @@ void MemoryRegion::sanityCheck() { } if (count > 1) { - display->freezeWithError("BBBB"); + FREEZE_WITH_ERROR("BBBB"); Debug::println("multiple 0xc0080bc!!!!"); } else if (count == 1) { @@ -99,16 +99,16 @@ void MemoryRegion::verifyMemoryNotFree(void* address, uint32_t spaceSize) { EmptySpaceRecord* emptySpaceRecord = (EmptySpaceRecord*)emptySpaces.getElementAddress(i); if (emptySpaceRecord->address == (uint32_t)address) { Debug::println("Exact address free!"); - display->freezeWithError("dddffffd"); + FREEZE_WITH_ERROR("dddffffd"); } else if (emptySpaceRecord->address <= (uint32_t)address && (emptySpaceRecord->address + emptySpaceRecord->length > (uint32_t)address)) { - display->freezeWithError("dddd"); + FREEZE_WITH_ERROR("dddd"); Debug::println("free mem overlap on left!"); } else if ((uint32_t)address <= (uint32_t)emptySpaceRecord->address && ((uint32_t)address + spaceSize > emptySpaceRecord->address)) { - display->freezeWithError("eeee"); + FREEZE_WITH_ERROR("eeee"); Debug::println("free mem overlap on right!"); } } @@ -124,7 +124,7 @@ static EmptySpaceRecord* recordToMergeWith; // spaceSize can even be 0 or less if you know it's going to get merged. inline void MemoryRegion::markSpaceAsEmpty(uint32_t address, uint32_t spaceSize, bool mayLookLeft, bool mayLookRight) { if ((address < start) || address > end) { - display->freezeWithError("M998"); + FREEZE_WITH_ERROR("M998"); return; } int32_t biggerRecordSearchFromIndex = 0; @@ -209,7 +209,7 @@ inline void MemoryRegion::markSpaceAsEmpty(uint32_t address, uint32_t spaceSize, newRecord.address = address; int32_t i = emptySpaces.searchMultiWordExact((uint32_t*)&newRecord); if (i != -1) { - display->freezeWithError("M123"); + FREEZE_WITH_ERROR("M123"); } i = emptySpaces.insertAtKeyMultiWord((uint32_t*)&newRecord, insertRangeBegin); #if ALPHA_OR_BETA_VERSION @@ -298,7 +298,7 @@ void* MemoryRegion::alloc(uint32_t requiredSize, bool makeStealable, void* thing int32_t extraSpaceSizeWithoutItsHeaders = allocatedSize - requiredSize - 8; if (extraSpaceSizeWithoutItsHeaders < -8) { - display->freezeWithError("M003"); + FREEZE_WITH_ERROR("M003"); } else { if (extraSpaceSizeWithoutItsHeaders <= minAlign) { @@ -403,7 +403,7 @@ void* MemoryRegion::alloc(uint32_t requiredSize, bool makeStealable, void* thing markSpaceAsEmpty(allocatedAddress + allocatedSize + 8, extraSpaceSizeWithoutItsHeaders, false, false); } else if (extraSpaceSizeWithoutItsHeaders < -8) { - display->freezeWithError("M004"); + FREEZE_WITH_ERROR("M004"); } } @@ -421,7 +421,7 @@ void* MemoryRegion::alloc(uint32_t requiredSize, bool makeStealable, void* thing #if ALPHA_OR_BETA_VERSION if (allocatedAddress < start || allocatedAddress > end) { //trying to allocate outside our region - display->freezeWithError("M002"); + FREEZE_WITH_ERROR("M002"); } #endif return (void*)allocatedAddress; @@ -821,11 +821,11 @@ void MemoryRegion::dealloc(void* address) { #if ALPHA_OR_BETA_VERSION if ((uint32_t)address < start || (uint32_t)address > end) { //deallocating outside our region - display->freezeWithError("M001"); + FREEZE_WITH_ERROR("M001"); } if ((*header & SPACE_TYPE_MASK) == SPACE_HEADER_EMPTY) { //double free - display->freezeWithError("M000"); + FREEZE_WITH_ERROR("M000"); } #endif diff --git a/src/deluge/model/clip/audio_clip.cpp b/src/deluge/model/clip/audio_clip.cpp index efd53c6dbe..8b25945ecf 100644 --- a/src/deluge/model/clip/audio_clip.cpp +++ b/src/deluge/model/clip/audio_clip.cpp @@ -67,7 +67,7 @@ AudioClip::AudioClip() : Clip(CLIP_TYPE_AUDIO) { AudioClip::~AudioClip() { if (recorder) { - display->freezeWithError("E278"); + FREEZE_WITH_ERROR("E278"); } // Sirhc actually got this in a V3.0.5 RC! No idea how. Also Qui got around V3.1.3. @@ -246,7 +246,7 @@ Clip* AudioClip::cloneAsNewOverdub(ModelStackWithTimelineCounter* modelStackOldC #if ALPHA_OR_BETA_VERSION if (!newClip->paramManager.summaries[0].paramCollection) { - display->freezeWithError("E421"); // Trying to diversify Leo's E410 + FREEZE_WITH_ERROR("E421"); // Trying to diversify Leo's E410 } #endif @@ -388,7 +388,7 @@ void AudioClip::resumePlayback(ModelStackWithTimelineCounter* modelStack, bool m #if ALPHA_OR_BETA_VERSION if (!playbackHandler.isEitherClockActive() || !modelStack->song->isClipActive(this)) { - display->freezeWithError("E430"); + FREEZE_WITH_ERROR("E430"); } #endif @@ -417,7 +417,7 @@ void AudioClip::resumePlayback(ModelStackWithTimelineCounter* modelStack, bool m int32_t sequenceSyncStartedNumTicksAgo = currentInternalTickCount - sequenceSyncStartedAtTickTrivialValue; if (sequenceSyncStartedNumTicksAgo < 0) { // Shouldn't happen if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("nofg"); // Ron got, Nov 2021. Wait no, he didn't have playback on! + FREEZE_WITH_ERROR("nofg"); // Ron got, Nov 2021. Wait no, he didn't have playback on! } sequenceSyncStartedNumTicksAgo = 0; // The show must go on } diff --git a/src/deluge/model/clip/clip.cpp b/src/deluge/model/clip/clip.cpp index 15884f22bd..d146abb12a 100644 --- a/src/deluge/model/clip/clip.cpp +++ b/src/deluge/model/clip/clip.cpp @@ -552,7 +552,7 @@ int32_t Clip::undoDetachmentFromOutput(ModelStackWithTimelineCounter* modelStack if (!success) { if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("E245"); + FREEZE_WITH_ERROR("E245"); } return ERROR_BUG; } @@ -938,13 +938,13 @@ int32_t Clip::solicitParamManager(Song* song, ParamManager* newParamManager, Cli int32_t error = paramManager.cloneParamCollectionsFrom(&otherClip->paramManager, false, true); if (error) { - display->freezeWithError("E050"); + FREEZE_WITH_ERROR("E050"); return error; } } // Unless I've done something wrong, there *has* to be another Clip if the Output didn't have a backed-up ParamManager. But, just in case else { - display->freezeWithError("E051"); + FREEZE_WITH_ERROR("E051"); return ERROR_UNSPECIFIED; } } diff --git a/src/deluge/model/clip/instrument_clip.cpp b/src/deluge/model/clip/instrument_clip.cpp index f6281cc0b1..51e3a36eb5 100644 --- a/src/deluge/model/clip/instrument_clip.cpp +++ b/src/deluge/model/clip/instrument_clip.cpp @@ -1095,7 +1095,7 @@ ModelStackWithNoteRow* InstrumentClip::getOrCreateNoteRowForYNote(int32_t yNote, thisNoteRow = getNoteRowForYNote(yNote); // Must re-get it if (ALPHA_OR_BETA_VERSION && !thisNoteRow) { - display->freezeWithError("E -1"); + FREEZE_WITH_ERROR("E -1"); } thisNoteRow->notes.empty(); // Undo our "total hack", above @@ -1492,7 +1492,7 @@ int32_t InstrumentClip::setNonAudioInstrument(Instrument* newInstrument, Song* s int32_t error = paramManager.setupMIDI(); if (error) { if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("E052"); + FREEZE_WITH_ERROR("E052"); } return error; } @@ -1606,7 +1606,7 @@ int32_t InstrumentClip::changeInstrument(ModelStackWithTimelineCounter* modelSta newInstrument, modelStack->song, newParamManager, favourClipForCloningParamManager); // Tell it not to setup patching - this will happen back here in changeInstrumentPreset() after all Drums matched up if (error) { - display->freezeWithError("E039"); + FREEZE_WITH_ERROR("E039"); return error; // TODO: we'll need to get the old Instrument back... } @@ -2034,7 +2034,7 @@ int32_t InstrumentClip::undoUnassignmentOfAllNoteRowsFromDrums(ModelStackWithTim if (!success) { if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("E229"); + FREEZE_WITH_ERROR("E229"); } return ERROR_BUG; } @@ -2125,7 +2125,7 @@ int32_t InstrumentClip::undoDetachmentFromOutput(ModelStackWithTimelineCounter* if (!paramManager.containsAnyMainParamCollections()) { if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("E230"); + FREEZE_WITH_ERROR("E230"); } return ERROR_BUG; } @@ -3066,7 +3066,7 @@ bool InstrumentClip::deleteSoundsWhichWontSound(Song* song) { if (ALPHA_OR_BETA_VERSION && noteRow->drum->type == DrumType::SOUND && ((SoundDrum*)noteRow->drum)->hasAnyVoices()) { - display->freezeWithError("E176"); + FREEZE_WITH_ERROR("E176"); } Drum* drum = noteRow->drum; @@ -3236,7 +3236,7 @@ int32_t InstrumentClip::getDistanceToNextNote(Note* givenNote, ModelStackWithNot int32_t InstrumentClip::getNoteRowId(NoteRow* noteRow, int32_t noteRowIndex) { #if ALPHA_OR_BETA_VERSION if (!noteRow) { - display->freezeWithError("E380"); + FREEZE_WITH_ERROR("E380"); } #endif if (output->type == InstrumentType::KIT) { @@ -3250,7 +3250,7 @@ int32_t InstrumentClip::getNoteRowId(NoteRow* noteRow, int32_t noteRowIndex) { NoteRow* InstrumentClip::getNoteRowFromId(int32_t id) { if (output->type == InstrumentType::KIT) { if (id < 0 || id >= noteRows.getNumElements()) { - display->freezeWithError("E177"); + FREEZE_WITH_ERROR("E177"); } return noteRows.getElement(id); } @@ -3801,7 +3801,7 @@ int32_t InstrumentClip::claimOutput(ModelStackWithTimelineCounter* modelStack) { // If wasn't enough RAM, we're really in trouble if (error) { - display->freezeWithError("E011"); + FREEZE_WITH_ERROR("E011"); haveNoDrum: thisNoteRow->drum = NULL; } diff --git a/src/deluge/model/consequence/consequence_clip_existence.cpp b/src/deluge/model/consequence/consequence_clip_existence.cpp index cc6aba8df1..38eebf369e 100644 --- a/src/deluge/model/consequence/consequence_clip_existence.cpp +++ b/src/deluge/model/consequence/consequence_clip_existence.cpp @@ -46,7 +46,7 @@ void ConsequenceClipExistence::prepareForDestruction(int32_t whichQueueActionIn, #if ALPHA_OR_BETA_VERSION if (clip->type == CLIP_TYPE_AUDIO) { if (((AudioClip*)clip)->recorder) { - display->freezeWithError("i002"); // Trying to diversify Qui's E278 + FREEZE_WITH_ERROR("i002"); // Trying to diversify Qui's E278 } } #endif @@ -68,14 +68,14 @@ int32_t ConsequenceClipExistence::revert(TimeType time, ModelStack* modelStack) int32_t error = clip->undoDetachmentFromOutput(modelStackWithTimelineCounter); if (error) { // This shouldn't actually happen, but if it does... #if ALPHA_OR_BETA_VERSION - display->freezeWithError("E046"); + FREEZE_WITH_ERROR("E046"); #endif return error; // Run away. This and the Clip(?) will get destructed, and everything should be ok! } #if ALPHA_OR_BETA_VERSION if (clip->type == CLIP_TYPE_AUDIO && !clip->paramManager.summaries[0].paramCollection) { - display->freezeWithError("E419"); // Trying to diversify Leo's E410 + FREEZE_WITH_ERROR("E419"); // Trying to diversify Leo's E410 } #endif @@ -116,7 +116,7 @@ int32_t ConsequenceClipExistence::revert(TimeType time, ModelStack* modelStack) clipIndex = clipArray->getIndexForClip(clip); if (clipIndex == -1) { - display->freezeWithError("E244"); + FREEZE_WITH_ERROR("E244"); } if (clipArray == &modelStackWithTimelineCounter->song->sessionClips) { @@ -143,14 +143,14 @@ int32_t ConsequenceClipExistence::revert(TimeType time, ModelStack* modelStack) #if ALPHA_OR_BETA_VERSION if (clip->type == CLIP_TYPE_AUDIO) { if (((AudioClip*)clip)->recorder) { - display->freezeWithError("i003"); // Trying to diversify Qui's E278 + FREEZE_WITH_ERROR("i003"); // Trying to diversify Qui's E278 } } #endif #if ALPHA_OR_BETA_VERSION if (clip->type == CLIP_TYPE_AUDIO && !clip->paramManager.summaries[0].paramCollection) { - display->freezeWithError("E420"); // Trying to diversify Leo's E410 + FREEZE_WITH_ERROR("E420"); // Trying to diversify Leo's E410 } #endif diff --git a/src/deluge/model/consequence/consequence_note_row_horizontal_shift.cpp b/src/deluge/model/consequence/consequence_note_row_horizontal_shift.cpp index ee27a12fee..3224637ae3 100644 --- a/src/deluge/model/consequence/consequence_note_row_horizontal_shift.cpp +++ b/src/deluge/model/consequence/consequence_note_row_horizontal_shift.cpp @@ -42,7 +42,7 @@ int32_t ConsequenceNoteRowHorizontalShift::revert(TimeType time, ModelStack* mod if (!modelStackWithNoteRow->getNoteRowAllowNull()) { #if ALPHA_OR_BETA_VERSION - display->freezeWithError("E377"); + FREEZE_WITH_ERROR("E377"); #endif return ERROR_BUG; } diff --git a/src/deluge/model/consequence/consequence_output_existence.cpp b/src/deluge/model/consequence/consequence_output_existence.cpp index b8fb751104..856adc0476 100644 --- a/src/deluge/model/consequence/consequence_output_existence.cpp +++ b/src/deluge/model/consequence/consequence_output_existence.cpp @@ -39,7 +39,7 @@ int32_t ConsequenceOutputExistence::revert(TimeType time, ModelStack* modelStack outputIndex = modelStack->song->removeOutputFromMainList(output); if (ALPHA_OR_BETA_VERSION && outputIndex == -1) { - display->freezeWithError("E263"); + FREEZE_WITH_ERROR("E263"); } output->prepareForHibernationOrDeletion(); diff --git a/src/deluge/model/drum/kit.cpp b/src/deluge/model/drum/kit.cpp index 16d6bf0445..90bc47af46 100644 --- a/src/deluge/model/drum/kit.cpp +++ b/src/deluge/model/drum/kit.cpp @@ -425,7 +425,7 @@ void Kit::drumRemoved(Drum* drum) { #if ALPHA_OR_BETA_VERSION int32_t i = drumsWithRenderingActive.searchExact((int32_t)drum); if (i != -1) { - display->freezeWithError("E321"); + FREEZE_WITH_ERROR("E321"); } #endif } @@ -493,13 +493,13 @@ bool Kit::renderGlobalEffectableForClip(ModelStackWithTimelineCounter* modelStac Drum* thisDrum = (Drum*)drumsWithRenderingActive.getKeyAtIndex(d); if (ALPHA_OR_BETA_VERSION && thisDrum->type != DrumType::SOUND) { - display->freezeWithError("E253"); + FREEZE_WITH_ERROR("E253"); } SoundDrum* soundDrum = (SoundDrum*)thisDrum; if (ALPHA_OR_BETA_VERSION && soundDrum->skippingRendering) { - display->freezeWithError("E254"); + FREEZE_WITH_ERROR("E254"); } ParamManager* drumParamManager; @@ -738,7 +738,7 @@ void Kit::setupWithoutActiveClip(ModelStack* modelStack) { ParamManager* paramManager = modelStackWithTimelineCounter->song->getBackedUpParamManagerPreferablyWithClip( (ModControllableAudio*)soundDrum, NULL); if (!paramManager) { - display->freezeWithError("E174"); + FREEZE_WITH_ERROR("E174"); } soundDrum->patcher.performInitialPatching(soundDrum, (ParamManagerForTimeline*)paramManager); @@ -795,7 +795,7 @@ void Kit::setupPatching(ModelStackWithTimelineCounter* modelStack) { ParamManager* paramManager = modelStack->song->getBackedUpParamManagerPreferablyWithClip((ModControllableAudio*)soundDrum, NULL); if (!paramManager) { - display->freezeWithError("E172"); + FREEZE_WITH_ERROR("E172"); } soundDrum->ensureInaccessibleParamPresetValuesWithoutKnobsAreZeroWithMinimalDetails( @@ -1124,7 +1124,7 @@ void Kit::offerReceivedNote(ModelStackWithTimelineCounter* modelStack, MIDIDevic if (thisNoteRow && thisDrum->type == DrumType::SOUND && !thisNoteRow->paramManager.containsAnyMainParamCollections()) { - display->freezeWithError("E326"); // Trying to catch an E313 that Vinz got + FREEZE_WITH_ERROR("E326"); // Trying to catch an E313 that Vinz got } beginAuditioningforDrum(modelStackWithNoteRow, thisDrum, velocity, mpeValues, channel); @@ -1355,15 +1355,15 @@ void Kit::beginAuditioningforDrum(ModelStackWithNoteRow* modelStack, Drum* drum, if (modelStack->getNoteRowAllowNull()) { paramManagerForDrum = &modelStack->getNoteRow()->paramManager; if (!paramManagerForDrum->containsAnyMainParamCollections() && drum->type == DrumType::SOUND) { - display->freezeWithError("E313"); // Vinz got this! + FREEZE_WITH_ERROR("E313"); // Vinz got this! } } else { if (drum->type == DrumType::SOUND) { paramManagerForDrum = modelStack->song->getBackedUpParamManagerPreferablyWithClip((SoundDrum*)drum, NULL); if (!paramManagerForDrum) { - display->freezeWithError( - "E314"); // Ron got this, June 2020, while "dragging" a row vertically in arranger + // Ron got this, June 2020, while "dragging" a row vertically in arranger + FREEZE_WITH_ERROR("E314"); } } } @@ -1402,7 +1402,7 @@ void Kit::endAuditioningForDrum(ModelStackWithNoteRow* modelStack, Drum* drum, i // If still here, haven't found paramManager yet paramManagerForDrum = modelStack->song->getBackedUpParamManagerPreferablyWithClip((SoundDrum*)drum, NULL); if (!paramManagerForDrum) { - display->freezeWithError("E312"); // Should make ALPHA_OR_BETA_VERSION after V3.0.0 release + FREEZE_WITH_ERROR("E312"); // Should make ALPHA_OR_BETA_VERSION after V3.0.0 release } } diff --git a/src/deluge/model/global_effectable/global_effectable.cpp b/src/deluge/model/global_effectable/global_effectable.cpp index a772bfb01d..053cccc3c9 100644 --- a/src/deluge/model/global_effectable/global_effectable.cpp +++ b/src/deluge/model/global_effectable/global_effectable.cpp @@ -49,6 +49,7 @@ GlobalEffectable::GlobalEffectable() { memset(allpassMemory, 0, sizeof(allpassMemory)); memset(&phaserMemory, 0, sizeof(phaserMemory)); editingComp = false; + currentCompParam = CompParam::RATIO; } void GlobalEffectable::cloneFrom(ModControllableAudio* other) { @@ -267,7 +268,17 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on, else if (modKnobMode == 4) { if (whichModEncoder == 0) { // Reverb if (on) { - view.cycleThroughReverbPresets(); + //if we're in full move/editingComp then we cycle through the comp params + //otherwise cycle reverb sizes + if (!editingComp) { + view.cycleThroughReverbPresets(); + } + else { + currentCompParam = + static_cast((util::to_underlying(currentCompParam) + 1) % maxCompParam); + const char* params[3] = {"ratio", "attack", "release"}; + display->popupTextTemporary(params[int(currentCompParam)]); + } } } else { @@ -282,50 +293,102 @@ bool GlobalEffectable::modEncoderButtonAction(uint8_t whichModEncoder, bool on, return false; // Some cases could lead here } -ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offset, int32_t whichModEncoder, - ModelStackWithAutoParam* modelStack) { + +int32_t GlobalEffectable::getKnobPosForNonExistentParam(int32_t whichModEncoder, ModelStackWithAutoParam* modelStack) { + int displayLevel = -64; if (*getModKnobMode() == 4) { + int current; + + //this is only reachable in comp editing mode, otherwise it's an existent param if (whichModEncoder == 1) { //sidechain (threshold) - int current = AudioEngine::mastercompressor.threshold >> 24; - current -= offset; - current = std::clamp(current, 1, 128); - indicator_leds::setKnobIndicatorLevel(1, std::max(0, 128 - current)); - AudioEngine::mastercompressor.threshold = lshiftAndSaturate<24>(current); - return ActionResult::DEALT_WITH; - } - else if (whichModEncoder == 0) { //ratio/reverb (we can only get here in comp editing mode) - int current = AudioEngine::mastercompressor.ratio >> 24; - current += offset; - //this range is ratio of 2 to infinity - current = std::clamp(current, 48, 112); - indicator_leds::setKnobIndicatorLevel(0, (current - 48) * 2); - AudioEngine::mastercompressor.ratio = lshiftAndSaturate<24>(current); - return ActionResult::DEALT_WITH; + current = AudioEngine::mastercompressor.rawThreshold >> 24; + displayLevel = current; + } + else if (whichModEncoder == 0) { + switch (currentCompParam) { + + case CompParam::RATIO: + current = AudioEngine::mastercompressor.rawRatio >> 24; + displayLevel = current; + break; + + case CompParam::ATTACK: + current = getLookupIndexFromValue(AudioEngine::mastercompressor.attack >> 2, attackRateTable, 50); + displayLevel = (current * 128) / 50; + break; + + case CompParam::RELEASE: + current = getLookupIndexFromValue(AudioEngine::mastercompressor.release >> 1, releaseRateTable, 50); + displayLevel = (current * 128) / 50; + break; + } } } - else if (*getModKnobMode() == 2) { - if (whichModEncoder == 1) { //attack - int current = getLookupIndexFromValue(AudioEngine::mastercompressor.attack >> 2, attackRateTable, 50); + return displayLevel - 64; +} + +ActionResult GlobalEffectable::modEncoderActionForNonExistentParam(int32_t offset, int32_t whichModEncoder, + ModelStackWithAutoParam* modelStack) { + if (*getModKnobMode() == 4) { + int current; + int displayLevel; + int ledLevel; + //this is only reachable in comp editing mode, otherwise it's an existent param + if (whichModEncoder == 1) { //sidechain (threshold) + current = (AudioEngine::mastercompressor.rawThreshold >> 24) - 64; current += offset; - current = std::clamp(current, 1, 50); - indicator_leds::setKnobIndicatorLevel(1, (current * 128) / 50); - AudioEngine::mastercompressor.attack = attackRateTable[current] << 2; - return ActionResult::DEALT_WITH; + current = std::clamp(current, -64, 64); + ledLevel = (64 + current); + displayLevel = ((ledLevel)*kMaxMenuValue) / 128; + AudioEngine::mastercompressor.rawThreshold = lshiftAndSaturate<24>(current + 64); + indicator_leds::setKnobIndicatorLevel(1, ledLevel); } - if (whichModEncoder == 0) { //release - int current = getLookupIndexFromValue(AudioEngine::mastercompressor.release >> 1, releaseRateTable, 50); - current += offset; - current = std::clamp(current, 2, 50); - indicator_leds::setKnobIndicatorLevel(0, (current * 128) / 50); - AudioEngine::mastercompressor.release = releaseRateTable[current] << 1; + else if (whichModEncoder == 0) { + switch (currentCompParam) { + + case CompParam::RATIO: + current = (AudioEngine::mastercompressor.rawRatio >> 24) - 64; + current += offset; + //this range is ratio of 2 to 20 + current = std::clamp(current, -64, 64); + ledLevel = (64 + current); + displayLevel = ((ledLevel)*kMaxMenuValue) / 128; + + AudioEngine::mastercompressor.rawRatio = lshiftAndSaturate<24>(current + 64); + break; + + case CompParam::ATTACK: + current = getLookupIndexFromValue(AudioEngine::mastercompressor.attack >> 2, attackRateTable, 50); + current += offset; + current = std::clamp(current, 1, 50); + displayLevel = current; + ledLevel = (displayLevel * 128) / 50; + + AudioEngine::mastercompressor.attack = attackRateTable[current] << 2; + break; - return ActionResult::DEALT_WITH; + case CompParam::RELEASE: + + current = getLookupIndexFromValue(AudioEngine::mastercompressor.release, releaseRateTable, 50); + current += offset; + current = std::clamp(current, 0, 50); + displayLevel = current; + ledLevel = (displayLevel * 128) / 50; + + AudioEngine::mastercompressor.release = releaseRateTable[current]; + + break; + } + indicator_leds::setKnobIndicatorLevel(0, ledLevel); } - } + char buffer[5]; + intToString(displayLevel, buffer); + display->displayPopup(buffer); + return ActionResult::DEALT_WITH; + } return ActionResult::NOT_DEALT_WITH; } - // Always check this doesn't return NULL! int32_t GlobalEffectable::getParameterFromKnob(int32_t whichModEncoder) { diff --git a/src/deluge/model/global_effectable/global_effectable.h b/src/deluge/model/global_effectable/global_effectable.h index e9f8815ef2..0a9743416d 100644 --- a/src/deluge/model/global_effectable/global_effectable.h +++ b/src/deluge/model/global_effectable/global_effectable.h @@ -55,14 +55,17 @@ class GlobalEffectable : public ModControllableAudio { void setupDelayWorkingState(DelayWorkingState* delayWorkingState, ParamManager* paramManager, bool shouldLimitDelayFeedback = false); bool isEditingComp() override { return editingComp; } + int32_t getKnobPosForNonExistentParam(int32_t whichModEncoder, ModelStackWithAutoParam* modelStack) override; ActionResult modEncoderActionForNonExistentParam(int32_t offset, int32_t whichModEncoder, ModelStackWithAutoParam* modelStack) override; dsp::filter::FilterSet filterSet; ModFXParam currentModFXParam; FilterType currentFilterType; bool editingComp; + CompParam currentCompParam; protected: + int maxCompParam = 0; virtual int32_t getParameterFromKnob(int32_t whichModEncoder); ModFXType getActiveModFXType(ParamManager* paramManager); diff --git a/src/deluge/model/global_effectable/global_effectable_for_song.cpp b/src/deluge/model/global_effectable/global_effectable_for_song.cpp index fbe3270749..a124c2effe 100644 --- a/src/deluge/model/global_effectable/global_effectable_for_song.cpp +++ b/src/deluge/model/global_effectable/global_effectable_for_song.cpp @@ -19,4 +19,6 @@ GlobalEffectableForSong::GlobalEffectableForSong() { modKnobMode = 1; + //attack and release can't go in the param manager so this keeps them from changing in clip comps + maxCompParam = 3; } diff --git a/src/deluge/model/instrument/midi_instrument.cpp b/src/deluge/model/instrument/midi_instrument.cpp index 70c6f6c388..ca31e71c94 100644 --- a/src/deluge/model/instrument/midi_instrument.cpp +++ b/src/deluge/model/instrument/midi_instrument.cpp @@ -439,10 +439,10 @@ int32_t MIDIInstrument::moveAutomationToDifferentCC(int32_t oldCC, int32_t newCC else { #if ALPHA_OR_BETA_VERSION if (modelStackWithAutoParam->paramCollection != modelStack->paramManager->getExpressionParamSet()) { - display->freezeWithError("E415"); + FREEZE_WITH_ERROR("E415"); } if (modelStackWithAutoParam->paramId >= kNumExpressionDimensions) { - display->freezeWithError("E416"); + FREEZE_WITH_ERROR("E416"); } #endif ((ExpressionParamSet*)modelStackWithAutoParam->paramCollection) diff --git a/src/deluge/model/mod_controllable/mod_controllable_audio.cpp b/src/deluge/model/mod_controllable/mod_controllable_audio.cpp index 8f8aba0418..66f567ec35 100644 --- a/src/deluge/model/mod_controllable/mod_controllable_audio.cpp +++ b/src/deluge/model/mod_controllable/mod_controllable_audio.cpp @@ -1574,7 +1574,7 @@ ModelStackWithThreeMainThings* ModControllableAudio::addNoteRowIndexAndStuff(Mod InstrumentClip* clip = (InstrumentClip*)modelStack->getTimelineCounter(); #if ALPHA_OR_BETA_VERSION if (noteRowIndex >= clip->noteRows.getNumElements()) { - display->freezeWithError("E406"); + FREEZE_WITH_ERROR("E406"); } #endif noteRow = clip->noteRows.getElement(noteRowIndex); diff --git a/src/deluge/model/mod_controllable/mod_controllable_audio.h b/src/deluge/model/mod_controllable/mod_controllable_audio.h index 700c7f06bf..18c8702d3a 100644 --- a/src/deluge/model/mod_controllable/mod_controllable_audio.h +++ b/src/deluge/model/mod_controllable/mod_controllable_audio.h @@ -80,7 +80,7 @@ class ModControllableAudio : public ModControllable { static bool readParamTagFromFile(char const* tagName, ParamManagerForTimeline* paramManager, int32_t readAutomationUpToPos); static void initParams(ParamManager* paramManager); - void wontBeRenderedForAWhile(); + virtual void wontBeRenderedForAWhile(); void endStutter(ParamManagerForTimeline* paramManager); virtual bool setModFXType(ModFXType newType); bool offerReceivedCCToLearnedParams(MIDIDevice* fromDevice, uint8_t channel, uint8_t ccNumber, uint8_t value, diff --git a/src/deluge/model/model_stack.cpp b/src/deluge/model/model_stack.cpp index a7aa30a755..861972ec8e 100644 --- a/src/deluge/model/model_stack.cpp +++ b/src/deluge/model/model_stack.cpp @@ -32,7 +32,7 @@ ModelStackWithThreeMainThings* ModelStackWithTimelineCounter::addNoteRowAndExtra #if ALPHA_OR_BETA_VERSION if (!newNoteRow->paramManager.containsAnyParamCollectionsIncludingExpression()) { - display->freezeWithError("E389"); + FREEZE_WITH_ERROR("E389"); } #endif diff --git a/src/deluge/model/model_stack.h b/src/deluge/model/model_stack.h index b698f1b05d..bdcb463173 100644 --- a/src/deluge/model/model_stack.h +++ b/src/deluge/model/model_stack.h @@ -146,7 +146,7 @@ class ModelStackWithTimelineCounter { inline TimelineCounter* getTimelineCounter() const { #if ALPHA_OR_BETA_VERSION if (!timelineCounter) { - display->freezeWithError("E369"); + FREEZE_WITH_ERROR("E369"); } #endif return timelineCounter; @@ -199,7 +199,7 @@ class ModelStackWithNoteRow : public ModelStackWithNoteRowId { inline NoteRow* getNoteRow() const { #if ALPHA_OR_BETA_VERSION if (!noteRow) { - display->freezeWithError("E379"); + FREEZE_WITH_ERROR("E379"); } #endif return noteRow; diff --git a/src/deluge/model/note/note_row.cpp b/src/deluge/model/note/note_row.cpp index b8c532cee5..839bbe5c6c 100644 --- a/src/deluge/model/note/note_row.cpp +++ b/src/deluge/model/note/note_row.cpp @@ -1104,7 +1104,7 @@ int32_t NoteRow::editNoteRepeatAcrossAllScreens(int32_t editPos, int32_t squareW } #if ALPHA_OR_BETA_VERSION else if (numToDelete < 0) { // If we overshot somehow - display->freezeWithError("E329"); + FREEZE_WITH_ERROR("E329"); } #endif @@ -3210,7 +3210,7 @@ void NoteRow::setDrum(Drum* newDrum, Kit* kit, ModelStackWithNoteRow* modelStack // If there also was no RAM... if (!paramManager.containsAnyMainParamCollections()) { - display->freezeWithError("E101"); + FREEZE_WITH_ERROR("E101"); } } @@ -3218,7 +3218,7 @@ void NoteRow::setDrum(Drum* newDrum, Kit* kit, ModelStackWithNoteRow* modelStack else { int32_t error = paramManager.setupWithPatching(); if (error) { - display->freezeWithError("E010"); // If there also was no RAM, we're really in trouble. + FREEZE_WITH_ERROR("E010"); // If there also was no RAM, we're really in trouble. } Sound::initParams(¶mManager); diff --git a/src/deluge/model/output.cpp b/src/deluge/model/output.cpp index bcd6583e1e..5b1ee59386 100644 --- a/src/deluge/model/output.cpp +++ b/src/deluge/model/output.cpp @@ -171,7 +171,7 @@ ParamManager* Output::getParamManager(Song* song) { ParamManager* paramManager = song->getBackedUpParamManagerPreferablyWithClip((ModControllableAudio*)toModControllable(), NULL); if (!paramManager) { - display->freezeWithError("E170"); + FREEZE_WITH_ERROR("E170"); } return paramManager; } @@ -426,11 +426,11 @@ void Output::endAnyArrangementRecording(Song* song, int32_t actualEndPosInternal int32_t i = clipInstances.search(actualEndPosInternalTicks, LESS); ClipInstance* clipInstance = clipInstances.getElement(i); if (ALPHA_OR_BETA_VERSION && !clipInstance) { - display->freezeWithError("E261"); + FREEZE_WITH_ERROR("E261"); } if (ALPHA_OR_BETA_VERSION && clipInstance->clip != activeClip) { // Michael B got, in 3.2.0-alpha10. Possibly a general memory corruption thing? - display->freezeWithError("E262"); + FREEZE_WITH_ERROR("E262"); } int32_t lengthSoFarInternalTicks = actualEndPosInternalTicks - clipInstance->pos; diff --git a/src/deluge/model/sample/sample.cpp b/src/deluge/model/sample/sample.cpp index b3f07bbc57..2d66407823 100644 --- a/src/deluge/model/sample/sample.cpp +++ b/src/deluge/model/sample/sample.cpp @@ -44,7 +44,7 @@ extern "C" { #if SAMPLE_DO_LOCKS #define LOCK_ENTRY \ if (lock) { \ - display->freezeWithError("i024"); \ + FREEZE_WITH_ERROR("i024"); \ } \ lock = true; #define LOCK_EXIT lock = false; @@ -134,7 +134,7 @@ void Sample::deletePercCache(bool beingDestructed) { // If any of them still has a "reason", well, it shouldn't if (ALPHA_OR_BETA_VERSION && percCacheClusters[reversed][c]->numReasonsToBeLoaded) { - display->freezeWithError("E137"); + FREEZE_WITH_ERROR("E137"); } audioFileManager.deallocateCluster(percCacheClusters[reversed][c]); @@ -383,7 +383,7 @@ int32_t Sample::fillPercCache(TimeStretcher* timeStretcher, int32_t startPosSamp percClusterIndexStart = (uint32_t)startPosSamples >> (audioFileManager.clusterSizeMagnitude + kPercBufferReductionMagnitude); if (ALPHA_OR_BETA_VERSION && percClusterIndexStart >= numPercCacheClusters) { - display->freezeWithError("E138"); + FREEZE_WITH_ERROR("E138"); } Cluster* clusterHere = percCacheClusters[reversed][percClusterIndexStart]; #if ALPHA_OR_BETA_VERSION @@ -394,7 +394,7 @@ int32_t Sample::fillPercCache(TimeStretcher* timeStretcher, int32_t startPosSamp & ((1 << audioFileManager.clusterSizeMagnitude + kPercBufferReductionMagnitude) - 1)) { // If Cluster has been stolen, the zones should have been updated, so we shouldn't be here Debug::println(startPosSamples); - display->freezeWithError("E139"); + FREEZE_WITH_ERROR("E139"); } } #endif @@ -419,11 +419,11 @@ int32_t Sample::fillPercCache(TimeStretcher* timeStretcher, int32_t startPosSamp if (percClusterIndexEnd != percClusterIndexStart) { #if ALPHA_OR_BETA_VERSION if (percClusterIndexEnd >= numPercCacheClusters) { - display->freezeWithError("E140"); + FREEZE_WITH_ERROR("E140"); } if (!percCacheClusters[reversed][percClusterIndexEnd]) { - display->freezeWithError( - "E141"); // If Cluster has been stolen, the zones should have been updated, so we shouldn't be here + // If Cluster has been stolen, the zones should have been updated, so we shouldn't be here + FREEZE_WITH_ERROR("E141"); } #endif timeStretcher->rememberPercCacheCluster(percCacheClusters[reversed][percClusterIndexEnd]); @@ -528,7 +528,7 @@ int32_t Sample::fillPercCache(TimeStretcher* timeStretcher, int32_t startPosSamp int32_t percClusterIndex = startPosSamples >> (audioFileManager.clusterSizeMagnitude + kPercBufferReductionMagnitude); if (ALPHA_OR_BETA_VERSION && percClusterIndex >= numPercCacheClusters) { - display->freezeWithError("E136"); + FREEZE_WITH_ERROR("E136"); } if (!percCacheClusters[reversed][percClusterIndex]) { //Debug::println("allocating perc cache Cluster!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); @@ -725,7 +725,7 @@ bool Sample::getAveragesForCrossfade(int32_t* totals, int32_t startBytePos, int3 // This can happen. Not 100% sure if it should, but we'll return false just below in this case anyway, so I think it's ok if (ALPHA_OR_BETA_VERSION && startBytePos < (int32_t)audioDataStartPosBytes) { - display->freezeWithError("E283"); + FREEZE_WITH_ERROR("E283"); } int32_t startSamplePos = (uint32_t)(startBytePos - audioDataStartPosBytes) / (uint8_t)bytesPerSample; @@ -765,7 +765,7 @@ bool Sample::getAveragesForCrossfade(int32_t* totals, int32_t startBytePos, int3 if (ALPHA_OR_BETA_VERSION && (readByte < audioDataStartPosBytes - 1 || readByte >= audioDataStartPosBytes + audioDataLengthBytes)) { - display->freezeWithError("FFFF"); + FREEZE_WITH_ERROR("FFFF"); } do { @@ -773,14 +773,14 @@ bool Sample::getAveragesForCrossfade(int32_t* totals, int32_t startBytePos, int3 if (ALPHA_OR_BETA_VERSION && (readByte < audioDataStartPosBytes - 1 || readByte >= audioDataStartPosBytes + audioDataLengthBytes)) { - display->freezeWithError("E432"); // Was "GGGG". Sven may have gotten. + FREEZE_WITH_ERROR("E432"); // Was "GGGG". Sven may have gotten. } int32_t whichCluster = readByte >> audioFileManager.clusterSizeMagnitude; if (ALPHA_OR_BETA_VERSION && (whichCluster < getFirstClusterIndexWithAudioData() || whichCluster >= getFirstClusterIndexWithNoAudioData())) { - display->freezeWithError("EEEE"); + FREEZE_WITH_ERROR("EEEE"); } Cluster* cluster = clusters.getElement(whichCluster)->cluster; @@ -815,7 +815,7 @@ bool Sample::getAveragesForCrossfade(int32_t* totals, int32_t startBytePos, int3 readByte += numSamplesThisRead * bytesPerSample * playDirection; numSamplesLeftThisAverage -= numSamplesThisRead; if (ALPHA_OR_BETA_VERSION && numSamplesLeftThisAverage < 0) { - display->freezeWithError("DDDD"); + FREEZE_WITH_ERROR("DDDD"); } } while (numSamplesLeftThisAverage); } @@ -853,7 +853,7 @@ uint8_t* Sample::prepareToReadPercCache(int32_t pixellatedPos, int32_t playDirec else { int32_t ourCluster = pixellatedPos >> audioFileManager.clusterSizeMagnitude; if (ALPHA_OR_BETA_VERSION && !percCacheClusters[reversed][ourCluster]) { - display->freezeWithError("E142"); + FREEZE_WITH_ERROR("E142"); } int32_t earliestCluster = *earliestPixellatedPos >> audioFileManager.clusterSizeMagnitude; @@ -890,19 +890,19 @@ void Sample::percCacheClusterStolen(Cluster* cluster) { #if ALPHA_OR_BETA_VERSION if (cluster->type != ClusterType::PERC_CACHE_FORWARDS && cluster->type != ClusterType::PERC_CACHE_REVERSED) { - display->freezeWithError("E149"); + FREEZE_WITH_ERROR("E149"); } if (!percCacheClusters[reversed]) { - display->freezeWithError("E134"); + FREEZE_WITH_ERROR("E134"); } if (cluster->clusterIndex >= numPercCacheClusters) { - display->freezeWithError("E135"); + FREEZE_WITH_ERROR("E135"); } if (!percCacheClusters[reversed][cluster->clusterIndex]) { - display->freezeWithError("i034"); // Trying to track down Steven G's E133 (Feb 2021). + FREEZE_WITH_ERROR("i034"); // Trying to track down Steven G's E133 (Feb 2021). } if (percCacheClusters[reversed][cluster->clusterIndex]->numReasonsToBeLoaded) { - display->freezeWithError("i035"); // Trying to track down Steven G's E133 (Feb 2021). + FREEZE_WITH_ERROR("i035"); // Trying to track down Steven G's E133 (Feb 2021). } #endif @@ -1744,11 +1744,11 @@ void Sample::numReasonsDecreasedToZero(char const* errorCode) { if (cluster->clusterIndex != c) { // Leo got! Aug 2020. Suspect some sort of memory corruption... And then Michael got, Feb 2021 - display->freezeWithError(errorCode); + FREEZE_WITH_ERROR(errorCode); } if (cluster->numReasonsToBeLoaded < 0) { - display->freezeWithError("E076"); + FREEZE_WITH_ERROR("E076"); } numClusterReasons += cluster->numReasonsToBeLoaded; @@ -1784,8 +1784,8 @@ void Sample::numReasonsDecreasedToZero(char const* errorCode) { } Debug::println("/reason dump---"); - display->freezeWithError( - "E078"); // LegsMechanical got, V4.0.0-beta2. https://forums.synthstrom.com/discussion/4106/v4-0-beta2-e078-crash-when-recording-audio-clip + // LegsMechanical got, V4.0.0-beta2. https://forums.synthstrom.com/discussion/4106/v4-0-beta2-e078-crash-when-recording-audio-clip + FREEZE_WITH_ERROR("E078"); } } #endif diff --git a/src/deluge/model/sample/sample_cache.cpp b/src/deluge/model/sample/sample_cache.cpp index 76b9f6fcd8..8a41563e08 100644 --- a/src/deluge/model/sample/sample_cache.cpp +++ b/src/deluge/model/sample/sample_cache.cpp @@ -49,10 +49,10 @@ void SampleCache::clusterStolen(int32_t clusterIndex) { #if ALPHA_OR_BETA_VERSION if (clusterIndex < 0) { - display->freezeWithError("E296"); + FREEZE_WITH_ERROR("E296"); } else if (clusterIndex >= numClusters) { - display->freezeWithError("E297"); + FREEZE_WITH_ERROR("E297"); } #endif @@ -71,16 +71,16 @@ void SampleCache::clusterStolen(int32_t clusterIndex) { #if ALPHA_OR_BETA_VERSION if (writeBytePos < 0) { - display->freezeWithError("E298"); + FREEZE_WITH_ERROR("E298"); } else if (writeBytePos >= waveformLengthBytes) { - display->freezeWithError("E299"); + FREEZE_WITH_ERROR("E299"); } int32_t numExistentClusters = getNumExistentClusters(writeBytePos); if (numExistentClusters != clusterIndex) { - display->freezeWithError("E295"); + FREEZE_WITH_ERROR("E295"); } clusters[clusterIndex] = NULL; // No need to remove this first Cluster from a queue or anything - that's already all done by the thing that's stealing it @@ -92,7 +92,7 @@ void SampleCache::unlinkClusters(int32_t startAtIndex, bool beingDestructed) { int32_t numExistentClusters = getNumExistentClusters(writeBytePos); for (int32_t i = startAtIndex; i < numExistentClusters; i++) { if (ALPHA_OR_BETA_VERSION && !clusters[i]) { - display->freezeWithError("E167"); + FREEZE_WITH_ERROR("E167"); } audioFileManager.deallocateCluster(clusters[i]); @@ -108,15 +108,15 @@ void SampleCache::setWriteBytePos(int32_t newWriteBytePos) { #if ALPHA_OR_BETA_VERSION if (newWriteBytePos < 0) { - display->freezeWithError("E300"); + FREEZE_WITH_ERROR("E300"); } if (newWriteBytePos > waveformLengthBytes) { - display->freezeWithError("E301"); + FREEZE_WITH_ERROR("E301"); } uint32_t bytesPerSample = sample->numChannels * kCacheByteDepth; if (newWriteBytePos != (uint32_t)newWriteBytePos / bytesPerSample * bytesPerSample) { - display->freezeWithError("E302"); + FREEZE_WITH_ERROR("E302"); } #endif @@ -129,7 +129,7 @@ void SampleCache::setWriteBytePos(int32_t newWriteBytePos) { writeBytePos = newWriteBytePos; if (ALPHA_OR_BETA_VERSION && getNumExistentClusters(writeBytePos) != newNumExistentClusters) { - display->freezeWithError("E294"); + FREEZE_WITH_ERROR("E294"); } } @@ -140,10 +140,10 @@ bool SampleCache::setupNewCluster(int32_t clusterIndex) { #if ALPHA_OR_BETA_VERSION if (clusterIndex >= numClusters) { - display->freezeWithError("E126"); + FREEZE_WITH_ERROR("E126"); } if (clusterIndex > getNumExistentClusters(writeBytePos)) { - display->freezeWithError("E293"); + FREEZE_WITH_ERROR("E293"); } #endif @@ -164,7 +164,7 @@ void SampleCache::prioritizeNotStealingCluster(int32_t clusterIndex) { if (GeneralMemoryAllocator::get().getRegion(clusters[clusterIndex]) != MEMORY_REGION_STEALABLE) { //clusters not in external - display->freezeWithError("C002"); + FREEZE_WITH_ERROR("C002"); return; // Sorta just have to do this } @@ -174,7 +174,7 @@ void SampleCache::prioritizeNotStealingCluster(int32_t clusterIndex) { // Remember, cache clusters never have "reasons", so we can assume these are already in one of the stealableClusterQueues, ready to be "stolen". #if ALPHA_OR_BETA_VERSION if (clusters[clusterIndex]->numReasonsToBeLoaded != 0) { - display->freezeWithError("C003"); //let's just check to make sure + FREEZE_WITH_ERROR("C003"); //let's just check to make sure } #endif // First Cluster @@ -193,7 +193,7 @@ void SampleCache::prioritizeNotStealingCluster(int32_t clusterIndex) { if (GeneralMemoryAllocator::get().getRegion(clusters[clusterIndex - 1]) != MEMORY_REGION_STEALABLE) { //clusters not in external - display->freezeWithError("C001"); + FREEZE_WITH_ERROR("C001"); return; // Sorta just have to do this } @@ -225,10 +225,10 @@ int32_t SampleCache::getNumExistentClusters(int32_t thisWriteBytePos) { #if ALPHA_OR_BETA_VERSION if (numExistentClusters < 0) { - display->freezeWithError("E303"); + FREEZE_WITH_ERROR("E303"); } if (numExistentClusters > numClusters) { - display->freezeWithError("E304"); + FREEZE_WITH_ERROR("E304"); } #endif diff --git a/src/deluge/model/sample/sample_cluster.cpp b/src/deluge/model/sample/sample_cluster.cpp index a4a1854d13..b432e26b42 100644 --- a/src/deluge/model/sample/sample_cluster.cpp +++ b/src/deluge/model/sample/sample_cluster.cpp @@ -46,8 +46,8 @@ SampleCluster::~SampleCluster() { Debug::print("uh oh, some reasons left... "); Debug::println(numReasonsToBeLoaded); - display->freezeWithError( - "E036"); // Bay_Mud got this, and thinks a FlashAir card might have been a catalyst. It still "shouldn't" be able to happen though. + // Bay_Mud got this, and thinks a FlashAir card might have been a catalyst. It still "shouldn't" be able to happen though. + FREEZE_WITH_ERROR("E036"); } #endif audioFileManager.deallocateCluster(cluster); @@ -62,10 +62,10 @@ void SampleCluster::ensureNoReason(Sample* sample) { Debug::println(sample->filePath.get()); if (cluster->numReasonsToBeLoaded >= 0) { - display->freezeWithError("E068"); + FREEZE_WITH_ERROR("E068"); } else { - display->freezeWithError("E069"); + FREEZE_WITH_ERROR("E069"); } delayMS(50); } @@ -106,10 +106,10 @@ Cluster* SampleCluster::getCluster(Sample* sample, uint32_t clusterIndex, int32_ #if 1 || ALPHA_OR_BETA_VERSION // Switching permanently on for now, as users on on V4.0.x have been getting E341. if (cluster->numReasonsToBeLoaded != 1) { - display->freezeWithError("i005"); // Diversifying Qui's E341. It should actually be exactly 1 + FREEZE_WITH_ERROR("i005"); // Diversifying Qui's E341. It should actually be exactly 1 } if (cluster->type != ClusterType::Sample) { - display->freezeWithError("E256"); // Cos I got E236 + FREEZE_WITH_ERROR("E256"); // Cos I got E236 } #endif @@ -126,14 +126,14 @@ Cluster* SampleCluster::getCluster(Sample* sample, uint32_t clusterIndex, int32_ justEnqueue: if (ALPHA_OR_BETA_VERSION && cluster->type != ClusterType::Sample) { - display->freezeWithError("E236"); // Cos Chris F got an E205 + FREEZE_WITH_ERROR("E236"); // Cos Chris F got an E205 } audioFileManager.enqueueCluster( cluster, priorityRating); // TODO: If that fails, it'll just get awkwardly forgotten about #if 1 || ALPHA_OR_BETA_VERSION // Switching permanently on for now, as users on on V4.0.x have been getting E341. if (cluster && cluster->numReasonsToBeLoaded <= 0) { - display->freezeWithError("i027"); // Diversifying Ron R's i004, which was diversifying Qui's E341 + FREEZE_WITH_ERROR("i027"); // Diversifying Ron R's i004, which was diversifying Qui's E341 } #endif } @@ -144,7 +144,7 @@ Cluster* SampleCluster::getCluster(Sample* sample, uint32_t clusterIndex, int32_ // cluster has (at least?) one reason - added above if (ALPHA_OR_BETA_VERSION && cluster->type != ClusterType::Sample) { - display->freezeWithError("E234"); // Cos Chris F got an E205 + FREEZE_WITH_ERROR("E234"); // Cos Chris F got an E205 } bool result = audioFileManager.loadCluster(cluster, 1); @@ -168,7 +168,7 @@ Cluster* SampleCluster::getCluster(Sample* sample, uint32_t clusterIndex, int32_ } #if 1 || ALPHA_OR_BETA_VERSION // Switching permanently on for now, as users on on V4.0.x have been getting E341. if (cluster && cluster->numReasonsToBeLoaded <= 0) { - display->freezeWithError("i026"); // Michael B got - insane. + FREEZE_WITH_ERROR("i026"); // Michael B got - insane. } #endif } @@ -179,7 +179,7 @@ Cluster* SampleCluster::getCluster(Sample* sample, uint32_t clusterIndex, int32_ #if 1 || ALPHA_OR_BETA_VERSION // Switching permanently on for now, as users on V4.1.3 have been getting E341. if (cluster && cluster->numReasonsToBeLoaded < 0) { - display->freezeWithError("i028"); // bnhrsch got this!! + FREEZE_WITH_ERROR("i028"); // bnhrsch got this!! } #endif @@ -203,14 +203,14 @@ Cluster* SampleCluster::getCluster(Sample* sample, uint32_t clusterIndex, int32_ #if 1 || ALPHA_OR_BETA_VERSION // Switching permanently on for now, as users on V4.0.x have been getting E341. if (cluster && cluster->numReasonsToBeLoaded <= 0) { - display->freezeWithError("i025"); // Diversifying Ron R's i004, which was diversifying Qui's E341 + FREEZE_WITH_ERROR("i025"); // Diversifying Ron R's i004, which was diversifying Qui's E341 } #endif } #if 1 || ALPHA_OR_BETA_VERSION // Switching permanently on for now, as users on V4.0.x have been getting E341. if (cluster && cluster->numReasonsToBeLoaded <= 0) { - display->freezeWithError("i004"); // Ron R got this! Diversifying Qui's E341 + FREEZE_WITH_ERROR("i004"); // Ron R got this! Diversifying Qui's E341 } #endif diff --git a/src/deluge/model/sample/sample_holder.cpp b/src/deluge/model/sample/sample_holder.cpp index 5dbc88a3a0..b3a9383893 100644 --- a/src/deluge/model/sample/sample_holder.cpp +++ b/src/deluge/model/sample/sample_holder.cpp @@ -43,7 +43,7 @@ SampleHolder::~SampleHolder() { unassignAllClusterReasons(true); #if ALPHA_OR_BETA_VERSION if (audioFile->numReasonsToBeLoaded <= 0) { - display->freezeWithError("E219"); // I put this here to try and catch an E004 Luc got + FREEZE_WITH_ERROR("E219"); // I put this here to try and catch an E004 Luc got } #endif audioFile->removeReason("E396"); @@ -130,7 +130,7 @@ void SampleHolder::setAudioFile(AudioFile* newSample, bool reversed, bool manual #if 1 || ALPHA_OR_BETA_VERSION if (!audioFile) { - display->freezeWithError("i031"); // Trying to narrow down E368 that Kevin F got + FREEZE_WITH_ERROR("i031"); // Trying to narrow down E368 that Kevin F got } #endif @@ -145,7 +145,7 @@ constexpr int32_t kMarkerSamplesBeforeToClaim = 150; void SampleHolder::claimClusterReasons(bool reversed, int32_t clusterLoadInstruction) { if (ALPHA_OR_BETA_VERSION && !audioFile) { - display->freezeWithError("E368"); + FREEZE_WITH_ERROR("E368"); } //unassignAllReasons(); // This now happens as part of reassessPosForMarker(), called below diff --git a/src/deluge/model/sample/sample_holder_for_voice.cpp b/src/deluge/model/sample/sample_holder_for_voice.cpp index f76e2655d0..d8a7c86065 100644 --- a/src/deluge/model/sample/sample_holder_for_voice.cpp +++ b/src/deluge/model/sample/sample_holder_for_voice.cpp @@ -67,7 +67,7 @@ void SampleHolderForVoice::claimClusterReasons(bool reversed, int32_t clusterLoa #if ALPHA_OR_BETA_VERSION if (!audioFile) { - display->freezeWithError("i030"); // Trying to narrow down E368 that Kevin F got + FREEZE_WITH_ERROR("i030"); // Trying to narrow down E368 that Kevin F got } #endif diff --git a/src/deluge/model/sample/sample_low_level_reader.cpp b/src/deluge/model/sample/sample_low_level_reader.cpp index e0e11cfcc6..70fb98162d 100644 --- a/src/deluge/model/sample/sample_low_level_reader.cpp +++ b/src/deluge/model/sample/sample_low_level_reader.cpp @@ -76,7 +76,7 @@ void SampleLowLevelReader::setupForPlayPosMovedIntoNewCluster(SamplePlaybackGuid #if ALPHA_OR_BETA_VERSION if (!clusters[0]) { - display->freezeWithError("i022"); + FREEZE_WITH_ERROR("i022"); } #endif @@ -146,7 +146,7 @@ void SampleLowLevelReader::setupReassessmentLocation(SamplePlaybackGuide* guide, #if ALPHA_OR_BETA_VERSION if (!clusters[0]) { - display->freezeWithError("i021"); + FREEZE_WITH_ERROR("i021"); } #endif @@ -195,7 +195,7 @@ void SampleLowLevelReader::setupReassessmentLocation(SamplePlaybackGuide* guide, if ((endPosWithinCurrentCluster + currentClusterIndex * audioFileManager.clusterSize - sample->audioDataStartPosBytes) % bytesPerSample) { - display->freezeWithError("E163"); + FREEZE_WITH_ERROR("E163"); } #endif reassessmentLocation = clusters[0]->data + endPosWithinCurrentCluster; @@ -339,7 +339,7 @@ bool SampleLowLevelReader::moveOnToNextCluster(SamplePlaybackGuide* guide, Sampl #if ALPHA_OR_BETA_VERSION if (!clusters[0]) { - display->freezeWithError("i019"); + FREEZE_WITH_ERROR("i019"); } #endif @@ -451,7 +451,7 @@ bool SampleLowLevelReader::changeClusterIfNecessary(SamplePlaybackGuide* guide, count++; if (count >= 1024) { // This happened one time! When stopping AudioClips from playing back, after recording and mucking around with SD card reaching full - display->freezeWithError("E227"); + FREEZE_WITH_ERROR("E227"); } #endif } @@ -566,7 +566,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t priorityRating) { if (ALPHA_OR_BETA_VERSION && phaseIncrement < 0) { - display->freezeWithError("E228"); + FREEZE_WITH_ERROR("E228"); } int32_t bytesPerSample = sample->numChannels * sample->byteDepth; @@ -595,7 +595,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E222"); + FREEZE_WITH_ERROR("E222"); } } } @@ -610,7 +610,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E305"); + FREEZE_WITH_ERROR("E305"); } } @@ -630,7 +630,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E306"); + FREEZE_WITH_ERROR("E306"); } } } @@ -642,7 +642,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E308"); + FREEZE_WITH_ERROR("E308"); } } @@ -675,7 +675,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E221"); + FREEZE_WITH_ERROR("E221"); } } } @@ -723,13 +723,13 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa if (ALPHA_OR_BETA_VERSION) { if (!clusters[0]) { - display->freezeWithError("E225"); + FREEZE_WITH_ERROR("E225"); } int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead <= 0) { - display->freezeWithError("E226"); + FREEZE_WITH_ERROR("E226"); } } @@ -744,7 +744,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E185"); + FREEZE_WITH_ERROR("E185"); } } } @@ -759,7 +759,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E223"); + FREEZE_WITH_ERROR("E223"); } } } @@ -789,7 +789,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa int32_t bytesLeftWhichMayBeRead = (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (ALPHA_OR_BETA_VERSION && bytesLeftWhichMayBeRead < 0) { - display->freezeWithError("E148"); + FREEZE_WITH_ERROR("E148"); } int32_t bytesWeWantToRead = samplesWeWantToReadThisWindow * bytesPerSample; @@ -810,10 +810,10 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa // This really really should never happen. if (ALPHA_OR_BETA_VERSION && phaseIncrementingLeftWhichMayBeDone < 0) { if (!clusters[0]) { - display->freezeWithError("E143"); + FREEZE_WITH_ERROR("E143"); } else { - display->freezeWithError("E000"); + FREEZE_WITH_ERROR("E000"); } } @@ -853,7 +853,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa (int32_t)((uint32_t)reassessmentLocation - (uint32_t)currentPlayPos) * guide->playDirection; if (ALPHA_OR_BETA_VERSION && bytesLeftWhichMayBeRead <= 0) { - display->freezeWithError("E001"); + FREEZE_WITH_ERROR("E001"); } // If there are actually less bytes remaining than we ideally wanted for this window... @@ -863,7 +863,7 @@ bool SampleLowLevelReader::considerUpcomingWindow(SamplePlaybackGuide* guide, Sa if (ALPHA_OR_BETA_VERSION && *numSamples <= 0) { Debug::print("bytesLeftWhichMayBeRead: "); Debug::println(bytesLeftWhichMayBeRead); - display->freezeWithError("E147"); // Crazily, Michael B got in Nov 2022, when "closing" a recorded loop. + FREEZE_WITH_ERROR("E147"); // Crazily, Michael B got in Nov 2022, when "closing" a recorded loop. } } } diff --git a/src/deluge/model/sample/sample_recorder.cpp b/src/deluge/model/sample/sample_recorder.cpp index 74677a1a19..f058c9a2b0 100644 --- a/src/deluge/model/sample/sample_recorder.cpp +++ b/src/deluge/model/sample/sample_recorder.cpp @@ -86,7 +86,7 @@ void SampleRecorder::detachSample() { // Some bug-hunting if (!cluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E345"); + FREEZE_WITH_ERROR("E345"); } cluster->numReasonsHeldBySampleRecorder--; @@ -103,12 +103,12 @@ void SampleRecorder::detachSample() { Cluster* cluster = sample->clusters.getElement(firstUnwrittenClusterIndex)->cluster; if (!cluster) { - display->freezeWithError("E363"); + FREEZE_WITH_ERROR("E363"); } // Some bug-hunting if (!cluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E346"); + FREEZE_WITH_ERROR("E346"); } cluster->numReasonsHeldBySampleRecorder--; @@ -156,7 +156,7 @@ int32_t SampleRecorder::setup(int32_t newNumChannels, AudioInputChannel newMode, // Bug hunting - newly gotten Cluster if (currentRecordCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E360"); + FREEZE_WITH_ERROR("E360"); } currentRecordCluster->numReasonsHeldBySampleRecorder++; @@ -330,7 +330,7 @@ int32_t SampleRecorder::cardRoutine() { // It should be impossible that anyone else still holds a "reason" to this Sample, as we can only be "aborted" // before AudioClip::finishLinearRecording() is called, and it's only then at the AudioClip becomes a "reason". if (sample->numReasonsToBeLoaded) { - display->freezeWithError("E282"); + FREEZE_WITH_ERROR("E282"); } #endif @@ -502,7 +502,7 @@ int32_t SampleRecorder::writeOneCompletedCluster() { // Trying to pin down E347 which Leo got, below Cluster* cluster = sample->clusters.getElement(writingClusterIndex)->cluster; if (!cluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E374"); + FREEZE_WITH_ERROR("E374"); } #endif @@ -517,7 +517,7 @@ int32_t SampleRecorder::writeOneCompletedCluster() { // Some bug-hunting if (!cluster->numReasonsHeldBySampleRecorder) { // Leo got!!! And Vinz, and keyman. May be solved now that fixed so detachSample() doesn't get called during card routine. - display->freezeWithError("E347"); + FREEZE_WITH_ERROR("E347"); } cluster->numReasonsHeldBySampleRecorder--; @@ -531,7 +531,7 @@ int32_t SampleRecorder::writeOneCompletedCluster() { int32_t SampleRecorder::finalizeRecordedFile() { if (ALPHA_OR_BETA_VERSION && (status == RECORDER_STATUS_ABORTED || hadCardError)) { - display->freezeWithError("E273"); + FREEZE_WITH_ERROR("E273"); } Debug::println("finalizing"); @@ -575,7 +575,7 @@ int32_t SampleRecorder::finalizeRecordedFile() { // Some bug-hunting if (!currentRecordCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E348"); + FREEZE_WITH_ERROR("E348"); } currentRecordCluster->numReasonsHeldBySampleRecorder--; @@ -677,11 +677,11 @@ int32_t SampleRecorder::finalizeRecordedFile() { // Do a last-ditch check that the SD address doesn't look invalid if (firstSampleCluster->sdAddress == 0) { - display->freezeWithError("E268"); + FREEZE_WITH_ERROR("E268"); } if ((firstSampleCluster->sdAddress - fileSystemStuff.fileSystem.database) & (fileSystemStuff.fileSystem.csize - 1)) { - display->freezeWithError("E269"); + FREEZE_WITH_ERROR("E269"); } audioDataLengthBytesAsWrittenToFile = sample->audioDataLengthBytes; @@ -695,7 +695,7 @@ int32_t SampleRecorder::finalizeRecordedFile() { // Some bug-hunting if (!cluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E349"); + FREEZE_WITH_ERROR("E349"); } cluster->numReasonsHeldBySampleRecorder--; @@ -800,7 +800,7 @@ int32_t SampleRecorder::createNextCluster() { // Bug hunting - newly gotten Cluster if (currentRecordCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E362"); + FREEZE_WITH_ERROR("E362"); } currentRecordCluster->numReasonsHeldBySampleRecorder++; @@ -835,7 +835,7 @@ void SampleRecorder::feedAudio(int32_t* __restrict__ inputAddress, int32_t numSa do { int32_t numSamplesThisCycle = numSamples; if (ALPHA_OR_BETA_VERSION && numSamplesThisCycle <= 0) { - display->freezeWithError("cccc"); + FREEZE_WITH_ERROR("cccc"); } // If haven't actually started recording yet cos we're compensating for lag... @@ -860,7 +860,7 @@ void SampleRecorder::feedAudio(int32_t* __restrict__ inputAddress, int32_t numSa numSamplesThisCycle = std::min(numSamplesThisCycle, samplesLeft); } if (ALPHA_OR_BETA_VERSION && numSamplesThisCycle <= 0) { - display->freezeWithError("bbbb"); + FREEZE_WITH_ERROR("bbbb"); } int32_t bytesPerSample = recordingNumChannels * 3; @@ -890,7 +890,7 @@ void SampleRecorder::feedAudio(int32_t* __restrict__ inputAddress, int32_t numSa } if (ALPHA_OR_BETA_VERSION && numSamplesThisCycle <= 0) { - display->freezeWithError("aaaa"); + FREEZE_WITH_ERROR("aaaa"); } int32_t* endInputNow = inputAddress + (numSamplesThisCycle << NUM_MONO_INPUT_CHANNELS_MAGNITUDE); @@ -1031,19 +1031,19 @@ void SampleRecorder::feedAudio(int32_t* __restrict__ inputAddress, int32_t numSa void SampleRecorder::endSyncedRecording(int32_t buttonLatencyForTempolessRecording) { #if ALPHA_OR_BETA_VERSION if (status == RECORDER_STATUS_CAPTURING_DATA_WAITING_TO_STOP) { - display->freezeWithError("E272"); + FREEZE_WITH_ERROR("E272"); } else if (status == RECORDER_STATUS_FINISHED_CAPTURING_BUT_STILL_WRITING) { - display->freezeWithError("E288"); + FREEZE_WITH_ERROR("E288"); } else if (status == RECORDER_STATUS_COMPLETE) { - display->freezeWithError("E289"); + FREEZE_WITH_ERROR("E289"); } else if (status == RECORDER_STATUS_ABORTED) { - display->freezeWithError("E290"); + FREEZE_WITH_ERROR("E290"); } else if (status == RECORDER_STATUS_AWAITING_DELETION) { - display->freezeWithError("E291"); + FREEZE_WITH_ERROR("E291"); } #endif @@ -1087,7 +1087,7 @@ void SampleRecorder::totalSampleLengthNowKnown(uint32_t totalLengthSamples, uint Cluster* cluster = firstSampleCluster->cluster; // It should still be there, cos it hasn't been written to card yet if (ALPHA_OR_BETA_VERSION && !cluster) { - display->freezeWithError("E274"); + FREEZE_WITH_ERROR("E274"); } audioDataLengthBytesAsWrittenToFile = sample->audioDataLengthBytes; @@ -1138,7 +1138,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t int32_t numClustersBeforeAction = ((idealFileSizeBeforeAction - 1) >> audioFileManager.clusterSizeMagnitude) + 1; // Rounds up if (ALPHA_OR_BETA_VERSION && numClustersBeforeAction > sample->clusters.getNumElements()) { - display->freezeWithError("E286"); + FREEZE_WITH_ERROR("E286"); } Cluster* nextReadCluster = NULL; @@ -1150,7 +1150,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentReadCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E350"); + FREEZE_WITH_ERROR("E350"); } currentReadCluster->numReasonsHeldBySampleRecorder--; @@ -1251,10 +1251,10 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Do a last-ditch check that the SD address doesn't look invalid if (sdAddress == 0) { - display->freezeWithError("E268"); + FREEZE_WITH_ERROR("E268"); } if ((sdAddress - fileSystemStuff.fileSystem.database) & (fileSystemStuff.fileSystem.csize - 1)) { - display->freezeWithError("E275"); + FREEZE_WITH_ERROR("E275"); } // Write the Cluster we just finished processing to card @@ -1274,7 +1274,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentWriteCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E351"); + FREEZE_WITH_ERROR("E351"); } currentWriteCluster->numReasonsHeldBySampleRecorder--; @@ -1288,7 +1288,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentReadCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E352"); + FREEZE_WITH_ERROR("E352"); } currentReadCluster->numReasonsHeldBySampleRecorder--; @@ -1297,7 +1297,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t if (nextReadCluster) { // Some bug-hunting if (!nextReadCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E353"); + FREEZE_WITH_ERROR("E353"); } nextReadCluster->numReasonsHeldBySampleRecorder--; @@ -1347,7 +1347,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentReadCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E354"); + FREEZE_WITH_ERROR("E354"); } currentReadCluster->numReasonsHeldBySampleRecorder--; @@ -1366,7 +1366,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentReadCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E355"); + FREEZE_WITH_ERROR("E355"); } currentReadCluster->numReasonsHeldBySampleRecorder--; @@ -1374,7 +1374,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentWriteCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E356"); + FREEZE_WITH_ERROR("E356"); } currentWriteCluster->numReasonsHeldBySampleRecorder--; @@ -1398,7 +1398,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentReadCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E357"); + FREEZE_WITH_ERROR("E357"); } currentReadCluster->numReasonsHeldBySampleRecorder--; @@ -1416,24 +1416,24 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t uint32_t numSectorsToWrite = ((bytesToWriteFinalCluster - 1) >> 9) + 1; if (numSectorsToWrite > (audioFileManager.clusterSize >> 9)) { - display->freezeWithError("E239"); + FREEZE_WITH_ERROR("E239"); } uint32_t sdAddress = sample->clusters.getElement(currentWriteClusterIndex)->sdAddress; // Do a last-ditch check that the SD address doesn't look invalid if (sdAddress == 0) { - display->freezeWithError("E268"); + FREEZE_WITH_ERROR("E268"); } if ((sdAddress - fileSystemStuff.fileSystem.database) & (fileSystemStuff.fileSystem.csize - 1)) { - display->freezeWithError("E276"); + FREEZE_WITH_ERROR("E276"); } DRESULT result = disk_write(0, (BYTE*)currentWriteCluster->data, sdAddress, numSectorsToWrite); // Some bug-hunting if (!currentWriteCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E358"); + FREEZE_WITH_ERROR("E358"); } currentWriteCluster->numReasonsHeldBySampleRecorder--; @@ -1467,7 +1467,7 @@ int32_t SampleRecorder::alterFile(int32_t action, int32_t lshiftAmount, uint32_t // Some bug-hunting if (!currentWriteCluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E359"); + FREEZE_WITH_ERROR("E359"); } currentWriteCluster->numReasonsHeldBySampleRecorder--; diff --git a/src/deluge/model/settings/runtime_feature_settings.cpp b/src/deluge/model/settings/runtime_feature_settings.cpp index 0f8d1d24e0..cb54d983ca 100644 --- a/src/deluge/model/settings/runtime_feature_settings.cpp +++ b/src/deluge/model/settings/runtime_feature_settings.cpp @@ -127,6 +127,10 @@ void RuntimeFeatureSettings::init() { SetupOnOffSetting(settings[RuntimeFeatureSettingType::AutomationShiftClip], deluge::l10n::getView(STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_SHIFT_CLIP), "automationShiftClip", RuntimeFeatureStateToggle::On); + // Disable Audition Pad Shortcuts in Automation View + SetupOnOffSetting(settings[RuntimeFeatureSettingType::AutomationDisableAuditionPadShortcuts], + deluge::l10n::getView(STRING_FOR_COMMUNITY_FEATURE_AUTOMATION_DISABLE_AUDITION_PAD_SHORTCUTS), + "automationDisableAuditionPadShortcuts", RuntimeFeatureStateToggle::On); // devSysexAllowed SetupOnOffSetting(settings[RuntimeFeatureSettingType::DevSysexAllowed], deluge::l10n::getView(STRING_FOR_COMMUNITY_FEATURE_DEV_SYSEX), "devSysexAllowed", diff --git a/src/deluge/model/settings/runtime_feature_settings.h b/src/deluge/model/settings/runtime_feature_settings.h index 4f5fd2cdb3..8d00980584 100644 --- a/src/deluge/model/settings/runtime_feature_settings.h +++ b/src/deluge/model/settings/runtime_feature_settings.h @@ -50,6 +50,7 @@ enum RuntimeFeatureSettingType : uint32_t { AutomationNudgeNote, AutomationShiftClip, AutomationInterpolate, + AutomationDisableAuditionPadShortcuts, DevSysexAllowed, SyncScalingAction, HighlightIncomingNotes, diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index 9cbe8ff6ba..c183f80ca6 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -138,7 +138,7 @@ Song::Song() : backedUpParamManagers(sizeof(BackedUpParamManager)) { masterCompressorAttack = attackRateTable[2] << 2; masterCompressorRelease = releaseRateTable[5] << 2; - masterCompressorThresh = ONE_Q31; + masterCompressorThresh = 0; masterCompressorRatio = ONE_Q31 >> 1; AudioEngine::mastercompressor.gainReduction = 0.0; @@ -1125,8 +1125,8 @@ void Song::writeToFile() { storageManager.writeOpeningTagBeginning("masterCompressor"); int32_t attack = AudioEngine::mastercompressor.attack; int32_t release = AudioEngine::mastercompressor.release; - int32_t thresh = AudioEngine::mastercompressor.threshold; - int32_t ratio = AudioEngine::mastercompressor.ratio; + int32_t thresh = AudioEngine::mastercompressor.rawThreshold; + int32_t ratio = AudioEngine::mastercompressor.rawRatio; storageManager.writeAttribute("attack", attack); storageManager.writeAttribute("release", release); @@ -2756,7 +2756,7 @@ void Song::deleteClipObject(Clip* clip, bool songBeingDestroyedToo, InstrumentRe #if ALPHA_OR_BETA_VERSION if (clip->type == CLIP_TYPE_AUDIO) { if (((AudioClip*)clip)->recorder) { - display->freezeWithError("i001"); // Trying to diversify Qui's E278 + FREEZE_WITH_ERROR("i001"); // Trying to diversify Qui's E278 } } #endif @@ -2971,7 +2971,7 @@ void Song::replaceInstrument(Instrument* oldOutput, Instrument* newOutput, bool for (Output* thisOutput = firstOutput; thisOutput; thisOutput = thisOutput->next) { if (thisOutput == newOutput) { display->cancelPopup(); - display->freezeWithError("i009"); + FREEZE_WITH_ERROR("i009"); } } @@ -3563,15 +3563,15 @@ void Song::deleteBackedUpParamManagersForClip(Clip* clip) { if (i >= 1) { if (backedUp->modControllable < lastModControllable) { - display->freezeWithError("E053"); + FREEZE_WITH_ERROR("E053"); } else if (backedUp->modControllable == lastModControllable) { if (backedUp->clip < lastClip) { - display->freezeWithError("E054"); + FREEZE_WITH_ERROR("E054"); } else if (backedUp->clip == lastClip) { - display->freezeWithError("E055"); + FREEZE_WITH_ERROR("E055"); } } } @@ -3903,7 +3903,7 @@ void Song::sortOutWhichClipsAreActiveWithoutSendingPGMs(ModelStack* modelStack, if (!getBackedUpParamManagerPreferablyWithClip(soundDrum, NULL)) { // If no backedUpParamManager... if (!findParamManagerForDrum(kit, soundDrum)) { // If no ParamManager with a NoteRow somewhere... - display->freezeWithError("E102"); + FREEZE_WITH_ERROR("E102"); } } } @@ -4006,7 +4006,7 @@ void Song::setHibernatingMIDIInstrument(MIDIInstrument* newInstrument) { void Song::deleteHibernatingMIDIInstrument() { if (hibernatingMIDIInstrument) { void* toDealloc = dynamic_cast(hibernatingMIDIInstrument); - hibernatingMIDIInstrument->~Instrument(); + hibernatingMIDIInstrument->~MIDIInstrument(); delugeDealloc(toDealloc); hibernatingMIDIInstrument = NULL; } @@ -4081,7 +4081,7 @@ void Song::ensureAllInstrumentsHaveAClipOrBackedUpParamManager(char const* error else { if (!getBackedUpParamManagerPreferablyWithClip((ModControllableAudio*)thisOutput->toModControllable(), NULL)) { - display->freezeWithError(errorMessageNormal); + FREEZE_WITH_ERROR(errorMessageNormal); } } } @@ -4097,14 +4097,14 @@ void Song::ensureAllInstrumentsHaveAClipOrBackedUpParamManager(char const* error // If has Clip, it shouldn't! if (getClipWithOutput(thisInstrument)) { - display->freezeWithError( - "E056"); // gtridr got, V4.0.0-beta2. Before I fixed memory corruption issues, so hopefully could just be that. + // gtridr got, V4.0.0-beta2. Before I fixed memory corruption issues, so hopefully could just be that. + FREEZE_WITH_ERROR("E056"); } else { if (!getBackedUpParamManagerPreferablyWithClip((ModControllableAudio*)thisInstrument->toModControllable(), NULL)) { - display->freezeWithError(errorMessageHibernating); + FREEZE_WITH_ERROR(errorMessageHibernating); } } } diff --git a/src/deluge/model/voice/voice.cpp b/src/deluge/model/voice/voice.cpp index 3bf752e68c..163108361a 100644 --- a/src/deluge/model/voice/voice.cpp +++ b/src/deluge/model/voice/voice.cpp @@ -2018,7 +2018,7 @@ void Voice::renderBasicSource(Sound* sound, ParamManagerForTimeline* paramManage instantUnassign: #ifdef TEST_SAMPLE_LOOP_POINTS - display->freezeWithError("YEP"); + FREEZE_WITH_ERROR("YEP"); #endif *unisonPartBecameInactive = true; diff --git a/src/deluge/model/voice/voice_sample.cpp b/src/deluge/model/voice/voice_sample.cpp index 887bc8c55e..93317d5be4 100644 --- a/src/deluge/model/voice/voice_sample.cpp +++ b/src/deluge/model/voice/voice_sample.cpp @@ -122,7 +122,7 @@ void VoiceSample::setupCacheLoopPoints(SamplePlaybackGuide* guide, Sample* sampl if (ALPHA_OR_BETA_VERSION && cacheEndPointBytes > cache->waveformLengthBytes) { Debug::println(cacheEndPointBytes); Debug::println(cache->waveformLengthBytes); - display->freezeWithError("E128"); + FREEZE_WITH_ERROR("E128"); } } @@ -182,7 +182,7 @@ int32_t VoiceSample::attemptLateSampleStart(SamplePlaybackGuide* voiceSource, Sa } if ((int64_t)(startAtByte - voiceSource->startPlaybackAtByte) * voiceSource->playDirection < 0) { - display->freezeWithError("E439"); // Chasing "E366". + FREEZE_WITH_ERROR("E439"); // Chasing "E366". } uint32_t startAtClusterIndex = startAtByte >> audioFileManager.clusterSizeMagnitude; @@ -192,7 +192,7 @@ int32_t VoiceSample::attemptLateSampleStart(SamplePlaybackGuide* voiceSource, Sa // This was a problem around V3.1.0 release, so currently keeping this check // even outside of ALPHA_OR_BETA_VERSION. // Sven got! 4.0.0-beta4. - display->freezeWithError("E366"); + FREEZE_WITH_ERROR("E366"); } int32_t finalClusterIndex = voiceSource->getFinalClusterIndex(sample, cache); // Think this is right... @@ -631,10 +631,10 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu // If we're here, then timeStretchRatio should be 16777216, and phaseIncrement should *not* if (ALPHA_OR_BETA_VERSION && timeStretchRatio != 16777216) { - display->freezeWithError("E240"); // This should have been caught and dealt with above + FREEZE_WITH_ERROR("E240"); // This should have been caught and dealt with above } if (ALPHA_OR_BETA_VERSION && phaseIncrement == 16777216) { - display->freezeWithError("E241"); // If this were the case, there'd be no reason to have a cache + FREEZE_WITH_ERROR("E241"); // If this were the case, there'd be no reason to have a cache } if (!stopReadingFromCache()) { @@ -674,7 +674,7 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu // This shouldn't happen - it gets checked for up at the start else if (ALPHA_OR_BETA_VERSION && bytesTilCacheEnd < 0) { - display->freezeWithError("E164"); + FREEZE_WITH_ERROR("E164"); } int32_t cachedClusterIndex = cacheBytePos >> audioFileManager.clusterSizeMagnitude; @@ -683,7 +683,7 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu Cluster* cacheCluster = cache->getCluster(cachedClusterIndex); if (ALPHA_OR_BETA_VERSION && !cacheCluster) { // If it got stolen - but we should have already detected this above - display->freezeWithError("E157"); + FREEZE_WITH_ERROR("E157"); } int32_t* __restrict__ readPos = (int32_t*)&cacheCluster->data[bytePosWithinCluster - 4 + kCacheByteDepth]; @@ -716,7 +716,7 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu } if (ALPHA_OR_BETA_VERSION && numSamplesThisCacheRead <= 0) { - display->freezeWithError("E156"); + FREEZE_WITH_ERROR("E156"); } // Ok, now we know how many samples we can read from the cache right now. Do it. @@ -897,7 +897,7 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu Cluster* cacheCluster = cache->getCluster(cacheClusterIndex); if (ALPHA_OR_BETA_VERSION && !cacheCluster) { // Check that the Cluster hasn't been stolen - but this should have been detected right at the start - display->freezeWithError("E166"); + FREEZE_WITH_ERROR("E166"); } cacheWritePos = &cacheCluster->data[bytePosWithinCluster]; @@ -925,7 +925,7 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu } if (ALPHA_OR_BETA_VERSION && numSamplesThisUncachedRead <= 0) { - display->freezeWithError("E155"); + FREEZE_WITH_ERROR("E155"); } } @@ -992,7 +992,7 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu #if ALPHA_OR_BETA_VERSION if (count >= 1024) { - display->freezeWithError("E169"); + FREEZE_WITH_ERROR("E169"); } count++; #endif @@ -1011,7 +1011,7 @@ bool VoiceSample::render(SamplePlaybackGuide* guide, int32_t* __restrict__ outpu (uint64_t)combinedIncrementingLeftToDoAbsolute / combinedIncrement; if (ALPHA_OR_BETA_VERSION && combinedIncrementsLeft > numSamplesThisUncachedRead) { Debug::println(combinedIncrementsLeft); - display->freezeWithError("E151"); + FREEZE_WITH_ERROR("E151"); } numSamplesThisUncachedRead = combinedIncrementsLeft; } diff --git a/src/deluge/model/voice/voice_vector.cpp b/src/deluge/model/voice/voice_vector.cpp index 2eada4e0e1..19b1adea3b 100644 --- a/src/deluge/model/voice/voice_vector.cpp +++ b/src/deluge/model/voice/voice_vector.cpp @@ -31,7 +31,7 @@ void VoiceVector::checkVoiceExists(Voice* voice, Sound* sound, char const* error int32_t i = searchMultiWordExact(searchWords); if (i == -1) { - display->freezeWithError(errorCode); + FREEZE_WITH_ERROR(errorCode); } } } diff --git a/src/deluge/modulation/arpeggiator.cpp b/src/deluge/modulation/arpeggiator.cpp index 6c1a7542e7..e9f920d4de 100644 --- a/src/deluge/modulation/arpeggiator.cpp +++ b/src/deluge/modulation/arpeggiator.cpp @@ -409,7 +409,7 @@ void Arpeggiator::switchNoteOn(ArpeggiatorSettings* settings, ArpReturnInstructi #if ALPHA_OR_BETA_VERSION if (whichNoteCurrentlyOnPostArp < 0 || whichNoteCurrentlyOnPostArp >= notes.getNumElements()) { - display->freezeWithError("E404"); + FREEZE_WITH_ERROR("E404"); } #endif diff --git a/src/deluge/modulation/automation/auto_param.cpp b/src/deluge/modulation/automation/auto_param.cpp index 9c6cf76592..4c41e9352c 100644 --- a/src/deluge/modulation/automation/auto_param.cpp +++ b/src/deluge/modulation/automation/auto_param.cpp @@ -262,7 +262,7 @@ skipThat : {} if (nodes.getNumElements()) { ParamNode* rightmostNode = nodes.getElement(nodes.getNumElements() - 1); if (rightmostNode->pos >= effectiveLength) { - display->freezeWithError("llll"); + FREEZE_WITH_ERROR("llll"); } } #endif @@ -705,7 +705,7 @@ int32_t AutoParam::processCurrentPos(ModelStackWithAutoParam const* modelStack, // we still contain automation, which I think we have to... Let's just verify that. #if ALPHA_OR_BETA_VERSION if (!isAutomated()) { - display->freezeWithError("E372"); + FREEZE_WITH_ERROR("E372"); } #endif modelStack->paramCollection->notifyParamModifiedInSomeWay(modelStack, oldValue, false, true, true); @@ -733,7 +733,7 @@ int32_t AutoParam::processCurrentPos(ModelStackWithAutoParam const* modelStack, ParamNode* rightmostNode = nodes.getElement(i); if (rightmostNode->pos >= effectiveLength) { nodes.deleteAtIndex(i); - //display->freezeWithError("jjjj"); // drbourbon got! And Quixotic7, on V4.0.0-beta8. + //FREEZE_WITH_ERROR("jjjj"); // drbourbon got! And Quixotic7, on V4.0.0-beta8. } } @@ -1012,14 +1012,14 @@ int32_t AutoParam::homogenizeRegion(ModelStackWithAutoParam const* modelStack, i #if ALPHA_OR_BETA_VERSION // Chasing "E433" / "GGGG" error (probably now largely solved - except got E435, see below). if (length <= 0) { - display->freezeWithError("E427"); + FREEZE_WITH_ERROR("E427"); } if (startPos < 0) { - display->freezeWithError("E437"); + FREEZE_WITH_ERROR("E437"); } // nodes.testSequentiality("E435"); // drbourbon got! March 2022. Now moved check to each caller. if (nodes.getNumElements() && nodes.getFirst()->pos < 0) { - display->freezeWithError("E436"); + FREEZE_WITH_ERROR("E436"); } // Should probably also check that stuff doesn't exist too far right - but that's a bit more complicated. #endif @@ -1037,7 +1037,7 @@ int32_t AutoParam::homogenizeRegion(ModelStackWithAutoParam const* modelStack, i length = maxLength; #if ALPHA_OR_BETA_VERSION if (length <= 0) { - display->freezeWithError("E428"); // Chasing Leo's GGGG error (probably now solved). + FREEZE_WITH_ERROR("E428"); // Chasing Leo's GGGG error (probably now solved). } #endif interpolateRightNode = false; @@ -1070,7 +1070,7 @@ int32_t AutoParam::homogenizeRegion(ModelStackWithAutoParam const* modelStack, i else { if constexpr (ALPHA_OR_BETA_VERSION || kCurrentFirmwareVersion <= FIRMWARE_4P0P0) { if (startPos < posAtWhichClipWillCut) { - display->freezeWithError("E445"); + FREEZE_WITH_ERROR("E445"); } } edgePositions[REGION_EDGE_RIGHT] = startPos; @@ -1082,7 +1082,7 @@ int32_t AutoParam::homogenizeRegion(ModelStackWithAutoParam const* modelStack, i length = edgePositions[REGION_EDGE_RIGHT] - edgePositions[REGION_EDGE_LEFT]; if constexpr (ALPHA_OR_BETA_VERSION) { if (edgePositions[REGION_EDGE_LEFT] >= edgePositions[REGION_EDGE_RIGHT]) { - display->freezeWithError("HHHH"); + FREEZE_WITH_ERROR("HHHH"); } } @@ -1217,7 +1217,7 @@ int32_t AutoParam::homogenizeRegion(ModelStackWithAutoParam const* modelStack, i if (nodes.getNumElements()) { ParamNode* rightmostNode = nodes.getElement(nodes.getNumElements() - 1); if (rightmostNode->pos >= effectiveLength) { - display->freezeWithError("iiii"); + FREEZE_WITH_ERROR("iiii"); } } #endif @@ -1237,24 +1237,24 @@ void AutoParam::homogenizeRegionTestSuccess(int32_t pos, int32_t regionEnd, int3 // Fine } else { - display->freezeWithError("E119"); + FREEZE_WITH_ERROR("E119"); } ParamNode* startNode = nodes.getElement(startI); ParamNode* endNode = nodes.getElement(endI); if (!startNode || !endNode) { - display->freezeWithError("E118"); + FREEZE_WITH_ERROR("E118"); } if (startNode->value != startValue) { - display->freezeWithError("E120"); + FREEZE_WITH_ERROR("E120"); } if (startNode->interpolated != interpolateStart) { - display->freezeWithError("E121"); + FREEZE_WITH_ERROR("E121"); } if (endNode->interpolated != interpolateEnd) { - display->freezeWithError("E122"); + FREEZE_WITH_ERROR("E122"); } } @@ -1714,7 +1714,7 @@ void AutoParam::trimToLength(uint32_t newLength, Action* action, ModelStackWithA int32_t newNumNodes = nodes.search(newLength, GREATER_OR_EQUAL); if (ALPHA_OR_BETA_VERSION && newNumNodes >= nodes.getNumElements()) { - display->freezeWithError("E315"); + FREEZE_WITH_ERROR("E315"); } // If still at least 2 nodes afterwards (1 is not allowed, actually wait it is now but let's keep this safe for now)... @@ -2566,7 +2566,7 @@ void AutoParam::nudgeNonInterpolatingNodesAtPos(int32_t pos, int32_t offset, int doWrap: // There should never be just one node if (ALPHA_OR_BETA_VERSION && nodes.getNumElements() == 1) { - display->freezeWithError("E335"); + FREEZE_WITH_ERROR("E335"); } int32_t ourValue = node->value; // Grab this before deleting stuff @@ -2596,7 +2596,7 @@ void AutoParam::nudgeNonInterpolatingNodesAtPos(int32_t pos, int32_t offset, int int32_t error = nodes.insertAtIndex( nextNodeI); // This shouldn't be able to fail, cos we just deleted a node if (ALPHA_OR_BETA_VERSION && error) { - display->freezeWithError("E333"); + FREEZE_WITH_ERROR("E333"); } } diff --git a/src/deluge/modulation/midi/midi_param_collection.cpp b/src/deluge/modulation/midi/midi_param_collection.cpp index 5cbb89d6b8..d3686f6c1a 100644 --- a/src/deluge/modulation/midi/midi_param_collection.cpp +++ b/src/deluge/modulation/midi/midi_param_collection.cpp @@ -279,19 +279,6 @@ bool MIDIParamCollection::mayParamInterpolate(int32_t paramId) { } int32_t MIDIParamCollection::knobPosToParamValue(int32_t knobPos, ModelStackWithAutoParam* modelStack) { - - if (getCurrentUI() - != &automationInstrumentClipView) { //let the automation instrument clip view handle the drawing of midi cc value - char buffer[5]; - int32_t valueForDisplay = knobPos; - valueForDisplay += 64; - if (valueForDisplay == 128) { - valueForDisplay = 127; - } - intToString(valueForDisplay, buffer); - display->displayPopup(buffer, 3, true); - } - return ParamCollection::knobPosToParamValue(knobPos, modelStack); } diff --git a/src/deluge/modulation/params/param_manager.cpp b/src/deluge/modulation/params/param_manager.cpp index 32d19dc66f..0d857303cf 100644 --- a/src/deluge/modulation/params/param_manager.cpp +++ b/src/deluge/modulation/params/param_manager.cpp @@ -48,7 +48,7 @@ ParamManager::~ParamManager() { #if ALPHA_OR_BETA_VERSION ParamManagerForTimeline* ParamManager::toForTimeline() { - display->freezeWithError("E407"); + FREEZE_WITH_ERROR("E407"); return NULL; } @@ -113,7 +113,7 @@ int32_t ParamManager::setupWithPatching() { void ParamManager::stealParamCollectionsFrom(ParamManager* other, bool stealExpressionParams) { #if ALPHA_OR_BETA_VERSION if (!other) { - display->freezeWithError("E413"); + FREEZE_WITH_ERROR("E413"); } #endif @@ -300,7 +300,7 @@ ExpressionParamSet* ParamManager::getOrCreateExpressionParamSet(bool forDrum) { ModelStackWithParamCollection* ParamManager::getPatchCableSet(ModelStackWithThreeMainThings const* modelStack) { #if ALPHA_OR_BETA_VERSION if (!summaries[2].paramCollection) { - display->freezeWithError("E412"); + FREEZE_WITH_ERROR("E412"); } #endif return modelStack->addParamCollection(summaries[2].paramCollection, &summaries[2]); @@ -315,7 +315,7 @@ ParamManagerForTimeline::ParamManagerForTimeline() { void ParamManagerForTimeline::ensureSomeParamCollections() { #if ALPHA_OR_BETA_VERSION if (!summaries[0].paramCollection) { - display->freezeWithError("E408"); + FREEZE_WITH_ERROR("E408"); } #endif } diff --git a/src/deluge/modulation/params/param_manager.h b/src/deluge/modulation/params/param_manager.h index a1a0951549..6b41ae6cc6 100644 --- a/src/deluge/modulation/params/param_manager.h +++ b/src/deluge/modulation/params/param_manager.h @@ -80,7 +80,7 @@ class ParamManager { inline MIDIParamCollection* getMIDIParamCollection() { #if ALPHA_OR_BETA_VERSION if (!summaries[0].paramCollection) { - display->freezeWithError("E409"); + FREEZE_WITH_ERROR("E409"); } #endif return (MIDIParamCollection*)summaries[0].paramCollection; @@ -89,7 +89,7 @@ class ParamManager { inline ParamCollectionSummary* getMIDIParamCollectionSummary() { #if ALPHA_OR_BETA_VERSION if (!summaries[0].paramCollection) { - display->freezeWithError("E409"); + FREEZE_WITH_ERROR("E409"); } #endif return &summaries[0]; @@ -98,7 +98,7 @@ class ParamManager { inline UnpatchedParamSet* getUnpatchedParamSet() { #if ALPHA_OR_BETA_VERSION if (!summaries[0].paramCollection) { - display->freezeWithError("E410"); + FREEZE_WITH_ERROR("E410"); } #endif return (UnpatchedParamSet*)summaries[0].paramCollection; @@ -107,7 +107,7 @@ class ParamManager { inline ParamCollectionSummary* getUnpatchedParamSetSummary() { #if ALPHA_OR_BETA_VERSION if (!summaries[0].paramCollection) { - display->freezeWithError("E410"); + FREEZE_WITH_ERROR("E410"); } #endif return &summaries[0]; @@ -116,7 +116,7 @@ class ParamManager { inline PatchedParamSet* getPatchedParamSet() { #if ALPHA_OR_BETA_VERSION if (!summaries[1].paramCollection) { - display->freezeWithError("E411"); + FREEZE_WITH_ERROR("E411"); } #endif return (PatchedParamSet*)summaries[1].paramCollection; @@ -125,7 +125,7 @@ class ParamManager { inline ParamCollectionSummary* getPatchedParamSetSummary() { #if ALPHA_OR_BETA_VERSION if (!summaries[1].paramCollection) { - display->freezeWithError("E411"); + FREEZE_WITH_ERROR("E411"); } #endif return &summaries[1]; @@ -134,7 +134,7 @@ class ParamManager { inline ParamCollectionSummary* getPatchCableSetSummary() { #if ALPHA_OR_BETA_VERSION if (!summaries[2].paramCollection) { - display->freezeWithError("E412"); + FREEZE_WITH_ERROR("E412"); } #endif return &summaries[2]; @@ -143,7 +143,7 @@ class ParamManager { inline PatchCableSet* getPatchCableSet() { #if ALPHA_OR_BETA_VERSION if (!summaries[2].paramCollection) { - display->freezeWithError("E412"); + FREEZE_WITH_ERROR("E412"); } #endif return (PatchCableSet*)summaries[2].paramCollection; diff --git a/src/deluge/modulation/params/param_set.cpp b/src/deluge/modulation/params/param_set.cpp index 0a1f41f464..6936da6249 100644 --- a/src/deluge/modulation/params/param_set.cpp +++ b/src/deluge/modulation/params/param_set.cpp @@ -553,21 +553,6 @@ void ExpressionParamSet::notifyParamModifiedInSomeWay(ModelStackWithAutoParam co // Displays text number. This will only actually end up getting used/seen on MIDI Clips, at channel/Clip level - not MPE/polyphonic. int32_t ExpressionParamSet::knobPosToParamValue(int32_t knobPos, ModelStackWithAutoParam* modelStack) { - - if (getCurrentUI() - != &automationInstrumentClipView) { //let the automation instrument clip view handle the drawing of midi cc value - char buffer[5]; - int32_t valueForDisplay = knobPos; - if (modelStack->paramId == 2) { // Just for aftertouch - valueForDisplay += 64; - if (valueForDisplay == 128) { - valueForDisplay = 127; - } - } - intToString(valueForDisplay, buffer); - display->displayPopup(buffer, 3, true); - } - // Everything but aftertouch gets handled by parent from here if (modelStack->paramId != 2) { return ParamSet::knobPosToParamValue(knobPos, modelStack); diff --git a/src/deluge/modulation/patch/patch_cable_set.cpp b/src/deluge/modulation/patch/patch_cable_set.cpp index de824bc01e..2e3f41a9c0 100644 --- a/src/deluge/modulation/patch/patch_cable_set.cpp +++ b/src/deluge/modulation/patch/patch_cable_set.cpp @@ -303,7 +303,7 @@ void PatchCableSet::setupPatching(ModelStackWithParamCollection const* modelStac // If getting crashes here, well I previously fixed a bug where sometimes the range-adjust*ed* cable was not "allowed", so // was not present here, but the adjust*ing* cable still was here, which this code can't handle. So check that again? if (thatDestination >= (&destinations[globality][numDestinations[globality]])) { - display->freezeWithError("E434"); + FREEZE_WITH_ERROR("E434"); } #endif } diff --git a/src/deluge/playback/mode/session.cpp b/src/deluge/playback/mode/session.cpp index 741a553855..60c93b74fc 100644 --- a/src/deluge/playback/mode/session.cpp +++ b/src/deluge/playback/mode/session.cpp @@ -1861,7 +1861,7 @@ int32_t Session::getCurrentSection() { } else { if (ALPHA_OR_BETA_VERSION && clip->section > kMaxNumSections) { - display->freezeWithError("E243"); + FREEZE_WITH_ERROR("E243"); } anyUnlaunchedLoopablesInSection[clip->section] = true; } diff --git a/src/deluge/playback/playback_handler.cpp b/src/deluge/playback/playback_handler.cpp index 4d41c16117..fe0f82ac50 100644 --- a/src/deluge/playback/playback_handler.cpp +++ b/src/deluge/playback/playback_handler.cpp @@ -1047,7 +1047,7 @@ int64_t PlaybackHandler::getCurrentInternalTickCount(uint32_t* timeRemainder) { #if ALPHA_OR_BETA_VERSION if (internalTickCount < 0) { // Trying to narrow down "nofg" error, which Ron got most recently (Nov 2021). Wait no, he didn't have playback on! - display->freezeWithError("E429"); + FREEZE_WITH_ERROR("E429"); } #endif @@ -1095,7 +1095,7 @@ float PlaybackHandler::getCurrentInternalTickFloatFollowingExternalClock() { // Should now be impossible for them to be at the same time, since we should be looking at one in the future and one not if (ALPHA_OR_BETA_VERSION && timeBetweenInputTicks <= 0) { - display->freezeWithError("E337"); + FREEZE_WITH_ERROR("E337"); } currentInputTick = diff --git a/src/deluge/processing/audio_output.cpp b/src/deluge/processing/audio_output.cpp index 5466f2c76c..992cff555e 100644 --- a/src/deluge/processing/audio_output.cpp +++ b/src/deluge/processing/audio_output.cpp @@ -376,7 +376,7 @@ Clip* AudioOutput::createNewClipForArrangementRecording(ModelStack* modelStack) #if ALPHA_OR_BETA_VERSION if (!newClip->paramManager.summaries[0].paramCollection) { - display->freezeWithError("E422"); // Trying to diversify Leo's E410 + FREEZE_WITH_ERROR("E422"); // Trying to diversify Leo's E410 } #endif diff --git a/src/deluge/processing/engines/audio_engine.cpp b/src/deluge/processing/engines/audio_engine.cpp index d8cac525cf..81ac68b0a1 100644 --- a/src/deluge/processing/engines/audio_engine.cpp +++ b/src/deluge/processing/engines/audio_engine.cpp @@ -390,29 +390,25 @@ void routine() { } #ifdef REPORT_CPU_USAGE -#define MIN_SAMPLES NUM_SAMPLES_FOR_CPU_USAGE_REPORT -#else -#define MINSAMPLES 16 -#endif +#define MINSAMPLES NUM_SAMPLES_FOR_CPU_USAGE_REPORT if (numSamples < (MINSAMPLES)) { audioRoutineLocked = false; return; } -#ifdef REPORT_CPU_USAGE + numSamples = NUM_SAMPLES_FOR_CPU_USAGE_REPORT; int32_t unadjustedNumSamplesBeforeLappingPlayHead = numSamples; #else +#define MINSAMPLES 16 - //// Disable cull smoothing until we know how to keep it from soft culling multiple times but audible hard culling anyway - // if (smoothedSamples < numSamples) { - // smoothedSamples = (numSamplesLastTime + numSamples) >> 1; - // } - // else { smoothedSamples = numSamples; - // } - // if (!bypassCulling) { - // numSamplesLastTime = numSamples; - // } + + if (numSamplesLastTime < numSamples) { + Debug::print("rendered "); + Debug::print(numSamplesLastTime); + Debug::print(" samples but output "); + Debug::println(numSamples); + } // Consider direness and culling - before increasing the number of samples int32_t numSamplesLimit = 40; //storageManager.devVarC; @@ -594,7 +590,14 @@ void routine() { } } } - + //this sets a floor on the number of samples at 16, avoiding the audio DMA catching up to the + //output when cutting rendering short for clock at critical times + //the max error is 0.3ms. At 100bpm 24ppq it is 25ms per pulse + //this works out to a 1% error in the absolute worse case of alternating + //no extension and max extension, approximately 10x better than average usb midi accuracy. + int32_t minSamples = std::min(unadjustedNumSamplesBeforeLappingPlayHead, MINSAMPLES); + numSamples = std::max(numSamples, minSamples); + numSamplesLastTime = numSamples; memset(&renderingBuffer, 0, numSamples * sizeof(StereoSample)); static int32_t reverbBuffer[SSI_TX_BUFFER_NUM_SAMPLES] __attribute__((aligned(CACHE_LINE_SIZE))); @@ -1241,7 +1244,7 @@ Voice* solicitVoice(Sound* forSound) { int32_t i = activeVoices.insertAtKeyMultiWord(keyWords); if (i == -1) { - // if (ALPHA_OR_BETA_VERSION) display->freezeWithError("E193"); // No, having run out of RAM here isn't a reason to not continue. + // if (ALPHA_OR_BETA_VERSION) FREEZE_WITH_ERROR("E193"); // No, having run out of RAM here isn't a reason to not continue. disposeOfVoice(newVoice); return NULL; } @@ -1409,11 +1412,15 @@ void slowRoutine() { - SSI_TX_BUFFER_NUM_SAMPLES) & (SSI_RX_BUFFER_NUM_SAMPLES - 1); - if (latencyWithinAppropriateWindow >= SSI_TX_BUFFER_NUM_SAMPLES) { + while (latencyWithinAppropriateWindow >= SSI_TX_BUFFER_NUM_SAMPLES) { i2sRXBufferPos += (SSI_TX_BUFFER_NUM_SAMPLES << (2 + NUM_MONO_INPUT_CHANNELS_MAGNITUDE)); if (i2sRXBufferPos >= (uint32_t)getRxBufferEnd()) { i2sRXBufferPos -= (SSI_RX_BUFFER_NUM_SAMPLES << (2 + NUM_MONO_INPUT_CHANNELS_MAGNITUDE)); } + latencyWithinAppropriateWindow = + (((rxBufferWriteAddr - (uint32_t)i2sRXBufferPos) >> (2 + NUM_MONO_INPUT_CHANNELS_MAGNITUDE)) + - SSI_TX_BUFFER_NUM_SAMPLES) + & (SSI_RX_BUFFER_NUM_SAMPLES - 1); } // Discard any LiveInputBuffers which aren't in use @@ -1472,7 +1479,7 @@ void discardRecorder(SampleRecorder* recorder) { count++; if (ALPHA_OR_BETA_VERSION && !*prevPointer) { - display->freezeWithError("E264"); + FREEZE_WITH_ERROR("E264"); } if (*prevPointer == recorder) { *prevPointer = recorder->next; diff --git a/src/deluge/processing/live/live_pitch_shifter.cpp b/src/deluge/processing/live/live_pitch_shifter.cpp index 4649565147..02aa3a0d9c 100644 --- a/src/deluge/processing/live/live_pitch_shifter.cpp +++ b/src/deluge/processing/live/live_pitch_shifter.cpp @@ -77,7 +77,7 @@ void LivePitchShifter::render(int32_t* __restrict__ outputBuffer, int32_t numSam LiveInputBuffer* liveInputBuffer = AudioEngine::getOrCreateLiveInputBuffer(inputType, false); if (ALPHA_OR_BETA_VERSION && !liveInputBuffer) { - display->freezeWithError("E165"); + FREEZE_WITH_ERROR("E165"); } liveInputBuffer->giveInput(numSamplesThisFunctionCall, AudioEngine::audioSampleTimer, inputType); @@ -371,7 +371,7 @@ void LivePitchShifter::hopEnd(int32_t phaseIncrement, LiveInputBuffer* liveInput //Debug::println(numRawSamplesProcessedAtNowTime); if (crossfadeProgress < 16777216) { Debug::println("last crossfade not finished"); - //if (ALPHA_OR_BETA_VERSION) display->freezeWithError("FADE"); + //if (ALPHA_OR_BETA_VERSION) FREEZE_WITH_ERROR("FADE"); } //Debug::println(phaseIncrement); diff --git a/src/deluge/processing/metronome/metronome.cpp b/src/deluge/processing/metronome/metronome.cpp index 1962149907..3b11045ef0 100644 --- a/src/deluge/processing/metronome/metronome.cpp +++ b/src/deluge/processing/metronome/metronome.cpp @@ -17,6 +17,10 @@ #include "processing/metronome/metronome.h" #include "dsp/stereo_sample.h" +#include "model/song/song.h" +#include "modulation/params/param_set.h" +#include "processing/engines/audio_engine.h" +#include "storage/flash_storage.h" Metronome::Metronome() { sounding = false; @@ -33,17 +37,29 @@ void Metronome::render(StereoSample* buffer, uint16_t numSamples) { if (!sounding) { return; } + int32_t volumePostFX; + if (currentSong) { + volumePostFX = getFinalParameterValueVolume( + 1 << FlashStorage::defaultMetronomeVolume, + cableToLinearParamShortcut(currentSong->paramManager.getUnpatchedParamSet()->getValue( + Param::Unpatched::GlobalEffectable::VOLUME))) + >> 1; + } + else { + volumePostFX = ONE_Q31; + } + q31_t high = multiply_32x32_rshift32(1 << FlashStorage::defaultMetronomeVolume, volumePostFX); StereoSample* thisSample = buffer; StereoSample* bufferEnd = buffer + numSamples; do { int32_t value; if (phase < 2147483648u) { - value = 8388608; + value = high; } else { - value = -8388608; + value = -high; } phase += phaseIncrement; diff --git a/src/deluge/processing/sound/sound.cpp b/src/deluge/processing/sound/sound.cpp index 4497ad37b9..95e8b74781 100644 --- a/src/deluge/processing/sound/sound.cpp +++ b/src/deluge/processing/sound/sound.cpp @@ -1552,7 +1552,7 @@ void Sound::allNotesOff(ModelStackWithThreeMainThings* modelStack, ArpeggiatorBa #if ALPHA_OR_BETA_VERSION if (!modelStack->paramManager) { // Previously we were allowed to receive a NULL paramManager, then would just crudely do an unassignAllVoices(). But I'm pretty sure this doesn't exist anymore? - display->freezeWithError("E403"); + FREEZE_WITH_ERROR("E403"); } #endif @@ -2366,11 +2366,11 @@ void Sound::unassignAllVoices() { if (ALPHA_OR_BETA_VERSION) { if (numVoicesAssigned > 0) { // ronronsen got error! https://forums.synthstrom.com/discussion/4090/e203-by-changing-a-drum-kit#latest - display->freezeWithError("E070"); + FREEZE_WITH_ERROR("E070"); } else if (numVoicesAssigned < 0) { // ronronsen got error! https://forums.synthstrom.com/discussion/4090/e203-by-changing-a-drum-kit#latest - display->freezeWithError("E071"); + FREEZE_WITH_ERROR("E071"); } } @@ -2405,7 +2405,7 @@ void Sound::confirmNumVoices(char const* error) { Uart::print(numVoicesAssigned); Uart::print(", but actually "); Uart::println(voiceCount); - display->freezeWithError(error); + FREEZE_WITH_ERROR(error); } int32_t reasonCountSources = 0; @@ -2433,7 +2433,7 @@ void Sound::confirmNumVoices(char const* error) { char buffer[5]; strcpy(buffer, error); buffer[0] = 'F'; - display->freezeWithError(buffer); + FREEZE_WITH_ERROR(buffer); } } */ @@ -4145,7 +4145,7 @@ void Sound::wontBeRenderedForAWhile() { // If it still thinks it's meant to be rendering, we did something wrong if (ALPHA_OR_BETA_VERSION && !skippingRendering) { - display->freezeWithError("E322"); + FREEZE_WITH_ERROR("E322"); } } diff --git a/src/deluge/processing/sound/sound_instrument.cpp b/src/deluge/processing/sound/sound_instrument.cpp index 467b970081..aa22af2a31 100644 --- a/src/deluge/processing/sound/sound_instrument.cpp +++ b/src/deluge/processing/sound/sound_instrument.cpp @@ -275,7 +275,7 @@ void SoundInstrument::setupWithoutActiveClip(ModelStack* modelStack) { ParamManager* paramManager = modelStackWithTimelineCounter->song->getBackedUpParamManagerPreferablyWithClip(this, NULL); if (!paramManager) { - display->freezeWithError("E173"); + FREEZE_WITH_ERROR("E173"); } patcher.performInitialPatching(this, paramManager); @@ -375,7 +375,7 @@ void SoundInstrument::sendNote(ModelStackWithThreeMainThings* modelStack, bool i #if ALPHA_OR_BETA_VERSION if (!modelStack->paramManager) { // Previously we were allowed to receive a NULL paramManager, then would just crudely do an unassignAllVoices(). But I'm pretty sure this doesn't exist anymore? - display->freezeWithError("E402"); + FREEZE_WITH_ERROR("E402"); } #endif ModelStackWithSoundFlags* modelStackWithSoundFlags = modelStack->addSoundFlags(); diff --git a/src/deluge/storage/audio/audio_file.cpp b/src/deluge/storage/audio/audio_file.cpp index 5b7cee0b89..0062878c54 100644 --- a/src/deluge/storage/audio/audio_file.cpp +++ b/src/deluge/storage/audio/audio_file.cpp @@ -514,7 +514,7 @@ void AudioFile::removeReason(char const* errorCode) { else if (numReasonsToBeLoaded < 0) { #if ALPHA_OR_BETA_VERSION - display->freezeWithError("E004"); // Luc got this! And Paolo. (Must have been years ago :D) + FREEZE_WITH_ERROR("E004"); // Luc got this! And Paolo. (Must have been years ago :D) #endif numReasonsToBeLoaded = 0; // Save it from crashing } diff --git a/src/deluge/storage/audio/audio_file_holder.cpp b/src/deluge/storage/audio/audio_file_holder.cpp index 9248d88c09..1cad25ee1e 100644 --- a/src/deluge/storage/audio/audio_file_holder.cpp +++ b/src/deluge/storage/audio/audio_file_holder.cpp @@ -65,7 +65,7 @@ void AudioFileHolder::setAudioFile(AudioFile* newAudioFile, bool reversed, bool unassignAllClusterReasons(); #if ALPHA_OR_BETA_VERSION if (audioFile->numReasonsToBeLoaded <= 0) { - display->freezeWithError("E220"); // I put this here to try and catch an E004 Luc got + FREEZE_WITH_ERROR("E220"); // I put this here to try and catch an E004 Luc got } #endif audioFile->removeReason("E391"); diff --git a/src/deluge/storage/audio/audio_file_manager.cpp b/src/deluge/storage/audio/audio_file_manager.cpp index 3deb0d06c6..99fcbbda2f 100644 --- a/src/deluge/storage/audio/audio_file_manager.cpp +++ b/src/deluge/storage/audio/audio_file_manager.cpp @@ -228,7 +228,7 @@ void AudioFileManager::deleteAnyTempRecordedSamplesFromMemory() { // If it's a temp-recorded one if (!((Sample*)audioFile)->tempFilePathForRecording.isEmpty()) { - //if (ALPHA_OR_BETA_VERSION && audioFile->numReasons) display->freezeWithError("E281"); // It definitely shouldn't still have any reasons + //if (ALPHA_OR_BETA_VERSION && audioFile->numReasons) FREEZE_WITH_ERROR("E281"); // It definitely shouldn't still have any reasons // No - it could still have a reason - the reason of its SampleRecorder. Scenario where this happened was: recording AudioClip (instance) // into Arranger when loading a new song, first causes Arranger playback to switch to Session playback, which causes // finishLinearRecording() on AudioClip, so when song-swap does happen, the AudioClip no longer has a recorder, so the recorder doesn't clear stuff, @@ -367,7 +367,7 @@ void AudioFileManager::deleteUnusedAudioFileFromMemoryIndexUnknown(AudioFile* au int32_t i = audioFiles.searchForExactObject(audioFile); if (i < 0) { #if ALPHA_OR_BETA_VERSION - display->freezeWithError("E401"); // Leo got. And me! But now I've solved. + FREEZE_WITH_ERROR("E401"); // Leo got. And me! But now I've solved. #endif } else { @@ -926,17 +926,17 @@ bool AudioFileManager::loadCluster(Cluster* cluster, int32_t minNumReasonsAfter) Sample* sample = cluster->sample; if (cluster->type != ClusterType::Sample) { - display->freezeWithError("E205"); // Chris F got this, so gonna leave checking in release build + FREEZE_WITH_ERROR("E205"); // Chris F got this, so gonna leave checking in release build } #if ALPHA_OR_BETA_VERSION if (cluster->numReasonsToBeLoaded <= 0) { // Ok, I think we know there's at least 1 reason at the point this function's called, because - display->freezeWithError("E204"); + FREEZE_WITH_ERROR("E204"); } // it'd only be in the loading queue if it had a "reason". if (!sample) { - display->freezeWithError("E206"); + FREEZE_WITH_ERROR("E206"); } #endif @@ -984,11 +984,11 @@ bool AudioFileManager::loadCluster(Cluster* cluster, int32_t minNumReasonsAfter) #if ALPHA_OR_BETA_VERSION if (cluster->type != ClusterType::Sample) { - display->freezeWithError("i023"); // Happened to me while thrash testing with reduced RAM + FREEZE_WITH_ERROR("i023"); // Happened to me while thrash testing with reduced RAM } if (cluster->numReasonsToBeLoaded < minNumReasonsAfter + 1) { - display->freezeWithError("i039"); // It's +1 because we haven't removed this function's "reason" yet. + FREEZE_WITH_ERROR("i039"); // It's +1 because we haven't removed this function's "reason" yet. } #endif @@ -1006,14 +1006,14 @@ bool AudioFileManager::loadCluster(Cluster* cluster, int32_t minNumReasonsAfter) #if ALPHA_OR_BETA_VERSION if (cluster->type != ClusterType::Sample) { - display->freezeWithError("E207"); + FREEZE_WITH_ERROR("E207"); } if (!cluster->sample) { - display->freezeWithError("E208"); + FREEZE_WITH_ERROR("E208"); } if (cluster->numReasonsToBeLoaded < minNumReasonsAfter + 1) { - display->freezeWithError("i038"); // It's +1 because we haven't removed this function's "reason" yet. + FREEZE_WITH_ERROR("i038"); // It's +1 because we haven't removed this function's "reason" yet. } #endif @@ -1026,7 +1026,7 @@ bool AudioFileManager::loadCluster(Cluster* cluster, int32_t minNumReasonsAfter) #if ALPHA_OR_BETA_VERSION if (cluster->numReasonsToBeLoaded < minNumReasonsAfter + 1) { - display->freezeWithError("i040"); // It's +1 because we haven't removed this function's "reason" yet. + FREEZE_WITH_ERROR("i040"); // It's +1 because we haven't removed this function's "reason" yet. } #endif @@ -1208,10 +1208,10 @@ bool AudioFileManager::loadCluster(Cluster* cluster, int32_t minNumReasonsAfter) #if ALPHA_OR_BETA_VERSION if (cluster->numReasonsToBeLoaded < minNumReasonsAfter) { - display->freezeWithError("i037"); + FREEZE_WITH_ERROR("i037"); } if (cluster->sample->clusters.getElement(cluster->clusterIndex)->cluster != cluster) { - display->freezeWithError("E438"); + FREEZE_WITH_ERROR("E438"); } #endif @@ -1307,7 +1307,7 @@ void AudioFileManager::loadAnyEnqueuedClusters(int32_t maxNum, bool mayProcessUs // Do the actual loading if (cluster->type != ClusterType::Sample) { - display->freezeWithError("E235"); // Cos Chris F got an E205 + FREEZE_WITH_ERROR("E235"); // Cos Chris F got an E205 } allowSomeUserActionsEvenWhenInCardRoutine = true; // Sorry!! @@ -1326,7 +1326,7 @@ void AudioFileManager::loadAnyEnqueuedClusters(int32_t maxNum, bool mayProcessUs else { if (cluster->type != ClusterType::Sample) { - display->freezeWithError("E237"); // Cos Chris F got an E205 + FREEZE_WITH_ERROR("E237"); // Cos Chris F got an E205 } enqueueCluster(cluster); // TODO: If that fails, it'll just get awkwardly forgotten about @@ -1366,7 +1366,7 @@ void AudioFileManager::removeReasonFromCluster(Cluster* cluster, char const* err cluster->numReasonsToBeLoaded--; if (cluster == clusterBeingLoaded && cluster->numReasonsToBeLoaded < minNumReasonsForClusterBeingLoaded) { - display->freezeWithError("E041"); // Sven got this! + FREEZE_WITH_ERROR("E041"); // Sven got this! } // If it's now zero, it's become available @@ -1374,7 +1374,7 @@ void AudioFileManager::removeReasonFromCluster(Cluster* cluster, char const* err // Bug hunting if (ALPHA_OR_BETA_VERSION && cluster->numReasonsHeldBySampleRecorder) { - display->freezeWithError("E364"); + FREEZE_WITH_ERROR("E364"); } // If it's still in the load queue, remove it from there. (We know that it isn't in the process of being loaded right now @@ -1401,7 +1401,7 @@ void AudioFileManager::removeReasonFromCluster(Cluster* cluster, char const* err Debug::print("reason remains on cluster of sample: "); Debug::println(cluster->sample->filePath.get()); } - display->freezeWithError(errorCode); + FREEZE_WITH_ERROR(errorCode); #else display->displayPopup(errorCode); // For non testers, just display the error code without freezing cluster->numReasonsToBeLoaded = 0; // Save it from crashing or anything diff --git a/src/deluge/storage/cluster/cluster.cpp b/src/deluge/storage/cluster/cluster.cpp index e6b5b94a76..f1e3c4279f 100644 --- a/src/deluge/storage/cluster/cluster.cpp +++ b/src/deluge/storage/cluster/cluster.cpp @@ -183,14 +183,14 @@ void Cluster::steal(char const* errorCode) { case ClusterType::Sample: if (ALPHA_OR_BETA_VERSION && !sample) { - display->freezeWithError("E181"); + FREEZE_WITH_ERROR("E181"); } sample->clusters.getElement(clusterIndex)->cluster = NULL; break; case ClusterType::SAMPLE_CACHE: if (ALPHA_OR_BETA_VERSION && !sampleCache) { - display->freezeWithError("E183"); + FREEZE_WITH_ERROR("E183"); } sampleCache->clusterStolen(clusterIndex); @@ -205,7 +205,7 @@ void Cluster::steal(char const* errorCode) { case ClusterType::PERC_CACHE_FORWARDS: case ClusterType::PERC_CACHE_REVERSED: if (ALPHA_OR_BETA_VERSION && !sample) { - display->freezeWithError("E184"); + FREEZE_WITH_ERROR("E184"); } sample->percCacheClusterStolen(this); break; diff --git a/src/deluge/storage/flash_storage.cpp b/src/deluge/storage/flash_storage.cpp index e2ca106a4d..85de2e2e0d 100644 --- a/src/deluge/storage/flash_storage.cpp +++ b/src/deluge/storage/flash_storage.cpp @@ -113,6 +113,12 @@ namespace FlashStorage { 114: GlobalMIDICommand::FILL channel + 1 115: GlobalMIDICommand::FILL noteCode + 1 116: GlobalMIDICommand::FILL product / vendor ids +117: defaultSessionLayout +118: defaultKeyboardLayout +119: gridUnarmEmptyPads +120: gridAllowGreenSelection +121: defaultGridActiveMode +122: defaultMetronomeVolume */ uint8_t defaultScale; @@ -133,6 +139,12 @@ uint8_t defaultBendRange[2] = { SessionLayoutType defaultSessionLayout; KeyboardLayoutType defaultKeyboardLayout; +bool gridUnarmEmptyPads; +bool gridAllowGreenSelection; +GridDefaultActiveMode defaultGridActiveMode; + +uint8_t defaultMetronomeVolume; + void resetSettings() { cvEngine.setCVVoltsPerOctave(0, 100); @@ -199,6 +211,12 @@ void resetSettings() { defaultSessionLayout = SessionLayoutType::SessionLayoutTypeRows; defaultKeyboardLayout = KeyboardLayoutType::KeyboardLayoutTypeIsomorphic; + + gridUnarmEmptyPads = false; + gridAllowGreenSelection = true; + defaultGridActiveMode = GridDefaultActiveModeSelection; + + defaultMetronomeVolume = kMaxMenuMetronomeVolumeValue; } void readSettings() { @@ -390,6 +408,16 @@ void readSettings() { defaultSessionLayout = static_cast(buffer[117]); defaultKeyboardLayout = static_cast(buffer[118]); + + gridUnarmEmptyPads = buffer[119]; + gridAllowGreenSelection = buffer[120]; + defaultGridActiveMode = static_cast(buffer[121]); + + defaultMetronomeVolume = buffer[122]; + if (defaultMetronomeVolume > kMaxMenuMetronomeVolumeValue + || defaultMetronomeVolume < kMinMenuMetronomeVolumeValue) { + defaultMetronomeVolume = kMaxMenuMetronomeVolumeValue; + } } void writeSettings() { @@ -495,6 +523,12 @@ void writeSettings() { buffer[117] = util::to_underlying(defaultSessionLayout); buffer[118] = util::to_underlying(defaultKeyboardLayout); + buffer[119] = gridUnarmEmptyPads; + buffer[120] = gridAllowGreenSelection; + buffer[121] = util::to_underlying(defaultGridActiveMode); + + buffer[122] = defaultMetronomeVolume; + R_SFLASH_EraseSector(0x80000 - 0x1000, SPIBSC_CH, SPIBSC_CMNCR_BSZ_SINGLE, 1, SPIBSC_OUTPUT_ADDR_24); R_SFLASH_ByteProgram(0x80000 - 0x1000, buffer, 256, SPIBSC_CH, SPIBSC_CMNCR_BSZ_SINGLE, SPIBSC_1BIT, SPIBSC_OUTPUT_ADDR_24); diff --git a/src/deluge/storage/flash_storage.h b/src/deluge/storage/flash_storage.h index 0a77a590a5..e7247d3da6 100644 --- a/src/deluge/storage/flash_storage.h +++ b/src/deluge/storage/flash_storage.h @@ -40,6 +40,12 @@ extern uint8_t defaultBendRange[2]; extern SessionLayoutType defaultSessionLayout; extern KeyboardLayoutType defaultKeyboardLayout; +extern bool gridUnarmEmptyPads; +extern bool gridAllowGreenSelection; +extern GridDefaultActiveMode defaultGridActiveMode; + +extern uint8_t defaultMetronomeVolume; + void readSettings(); void writeSettings(); void resetSettings(); diff --git a/src/deluge/storage/storage_manager.cpp b/src/deluge/storage/storage_manager.cpp index 5dc26f7571..7fe19b8e29 100644 --- a/src/deluge/storage/storage_manager.cpp +++ b/src/deluge/storage/storage_manager.cpp @@ -366,8 +366,8 @@ char const* StorageManager::readNextTagOrAttributeName() { default: #if ALPHA_OR_BETA_VERSION - display->freezeWithError( - "E365"); // Can happen with invalid files, though I'm implementing error checks whenever a user alerts me to a scenario. Fraser got this, Nov 2021. + // Can happen with invalid files, though I'm implementing error checks whenever a user alerts me to a scenario. Fraser got this, Nov 2021. + FREEZE_WITH_ERROR("E365"); #else __builtin_unreachable(); #endif @@ -742,7 +742,7 @@ char const* StorageManager::readTagOrAttributeValue() { return ""; default: - display->freezeWithError("BBBB"); + FREEZE_WITH_ERROR("BBBB"); __builtin_unreachable(); } } @@ -763,7 +763,7 @@ int32_t StorageManager::readTagOrAttributeValueInt() { return 0; default: - display->freezeWithError("BBBB"); + FREEZE_WITH_ERROR("BBBB"); __builtin_unreachable(); } } @@ -799,7 +799,7 @@ int32_t StorageManager::readTagOrAttributeValueString(String* string) { default: if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("BBBB"); + FREEZE_WITH_ERROR("BBBB"); } __builtin_unreachable(); } @@ -830,7 +830,7 @@ bool StorageManager::prepareToReadTagOrAttributeValueOneCharAtATime() { default: if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("CCCC"); + FREEZE_WITH_ERROR("CCCC"); } __builtin_unreachable(); } @@ -907,7 +907,7 @@ void StorageManager::exitTag(char const* exitTagName) { default: if (ALPHA_OR_BETA_VERSION) { - display->freezeWithError("AAAA"); // Really shouldn't be possible anymore, I feel fairly certain... + FREEZE_WITH_ERROR("AAAA"); // Really shouldn't be possible anymore, I feel fairly certain... } __builtin_unreachable(); } diff --git a/src/deluge/storage/wave_table/wave_table.cpp b/src/deluge/storage/wave_table/wave_table.cpp index bd17c2ce2f..e3f9017760 100644 --- a/src/deluge/storage/wave_table/wave_table.cpp +++ b/src/deluge/storage/wave_table/wave_table.cpp @@ -672,7 +672,7 @@ int32_t WaveTable::setup(Sample* sample, int32_t rawFileCycleSize, uint32_t audi if (!fftCFGThisBand) { #if ALPHA_OR_BETA_VERSION if (!b) { - display->freezeWithError("E390"); + FREEZE_WITH_ERROR("E390"); } #endif band->~WaveTableBand(); @@ -1083,7 +1083,7 @@ uint32_t WaveTable::render(int32_t* __restrict__ outputBuffer, int32_t numSample numIncrementsWeCanDoNow + 1; // +1 because we can only have to increment *between* the samples we're rendering. If can only do 1 increment, we can still render 2 samples. if (ALPHA_OR_BETA_VERSION && numSamplesThisCycle > numSamplesLeftToDo) { - display->freezeWithError("E386"); + FREEZE_WITH_ERROR("E386"); } } @@ -1166,7 +1166,7 @@ void WaveTable::numReasonsDecreasedToZero(char const* errorCode) { if (band->data) { #if ALPHA_OR_BETA_VERSION if (band->data->list) { - display->freezeWithError("E388"); + FREEZE_WITH_ERROR("E388"); } #endif GeneralMemoryAllocator::get().putStealableInQueue(band->data, STEALABLE_QUEUE_NO_SONG_WAVETABLE_BAND_DATA); diff --git a/src/deluge/storage/wave_table/wave_table_band_data.cpp b/src/deluge/storage/wave_table/wave_table_band_data.cpp index a04b30d4aa..9ca7b2f2e6 100644 --- a/src/deluge/storage/wave_table/wave_table_band_data.cpp +++ b/src/deluge/storage/wave_table/wave_table_band_data.cpp @@ -35,7 +35,7 @@ bool WaveTableBandData::mayBeStolen(void* thingNotToStealFrom) { void WaveTableBandData::steal(char const* errorCode) { #if ALPHA_OR_BETA_VERSION if (!waveTable || waveTable->numReasonsToBeLoaded) { - display->freezeWithError("E387"); + FREEZE_WITH_ERROR("E387"); } #endif diff --git a/src/deluge/util/algorithm/quick_sorter.cpp b/src/deluge/util/algorithm/quick_sorter.cpp index bb6bb93536..9989c022ea 100644 --- a/src/deluge/util/algorithm/quick_sorter.cpp +++ b/src/deluge/util/algorithm/quick_sorter.cpp @@ -90,7 +90,7 @@ void QuickSorter::sort(int32_t numElements) { for (int32_t i = 1; i < numElements; i++) { int32_t keyHere = getKey(i); if (keyHere < lastKey) { - display->freezeWithError("SORT"); + FREEZE_WITH_ERROR("SORT"); } lastKey = keyHere; } diff --git a/src/deluge/util/container/array/ordered_resizeable_array.cpp b/src/deluge/util/container/array/ordered_resizeable_array.cpp index af3e411719..ca7bab72dd 100644 --- a/src/deluge/util/container/array/ordered_resizeable_array.cpp +++ b/src/deluge/util/container/array/ordered_resizeable_array.cpp @@ -268,7 +268,7 @@ void OrderedResizeableArray::testSequentiality(char const* errorCode) { for (int32_t i = 0; i < getNumElements(); i++) { int32_t key = getKeyAtIndex(i); if (key <= lastKey) { - display->freezeWithError(errorCode); + FREEZE_WITH_ERROR(errorCode); } lastKey = key; @@ -310,7 +310,7 @@ void OrderedResizeableArrayWith32bitKey::testSearchMultiple() { for (int32_t t = 0; t < TEST_SEARCH_MULTIPLE_NUM_SEARCH_TERMS; t++) { while (getKeyAtIndex(i) < searchPos[t]) { if (i >= resultingIndexes[t]) { - //display->freezeWithError("FAIL"); + //FREEZE_WITH_ERROR("FAIL"); Debug::println("fail"); goto thatsDone; } diff --git a/src/deluge/util/container/array/ordered_resizeable_array_with_multi_word_key.cpp b/src/deluge/util/container/array/ordered_resizeable_array_with_multi_word_key.cpp index b02736589c..7369862355 100644 --- a/src/deluge/util/container/array/ordered_resizeable_array_with_multi_word_key.cpp +++ b/src/deluge/util/container/array/ordered_resizeable_array_with_multi_word_key.cpp @@ -131,12 +131,12 @@ void OrderedResizeableArrayWithMultiWordKey::testSequentiality(char const* error for (int j = 0; j < numWordsInKey; j++) { int32_t difference = wordsHere[j] - lastWords[j]; if (difference < 0) { - display->freezeWithError(errorCode); + FREEZE_WITH_ERROR(errorCode); } if (difference == 0) { if (j == numWordsInKey - 1) { //if we got here it's a duplicate key - display->freezeWithError(errorCode); + FREEZE_WITH_ERROR(errorCode); } } else { diff --git a/src/deluge/util/container/array/resizeable_array.cpp b/src/deluge/util/container/array/resizeable_array.cpp index 66108926f8..a1be99f097 100644 --- a/src/deluge/util/container/array/resizeable_array.cpp +++ b/src/deluge/util/container/array/resizeable_array.cpp @@ -32,13 +32,13 @@ #define LOCK_EXIT exitLock(); void ResizeableArray::freezeOnLock() { if (lock) { - display->freezeWithError("i008"); + FREEZE_WITH_ERROR("i008"); } lock = true; } void ResizeableArray::exitLock() { if (!lock) { - display->freezeWithError("i008"); + FREEZE_WITH_ERROR("i008"); } lock = false; } @@ -892,7 +892,7 @@ void ResizeableArray::setStaticMemory(void* newMemory, int32_t newMemorySize) { int32_t ResizeableArray::insertAtIndex(int32_t i, int32_t numToInsert, void* thingNotToStealFrom) { if (ALPHA_OR_BETA_VERSION && (i < 0 || i > numElements || numToInsert < 1)) { - display->freezeWithError("E280"); + FREEZE_WITH_ERROR("E280"); } LOCK_ENTRY @@ -919,7 +919,7 @@ int32_t ResizeableArray::insertAtIndex(int32_t i, int32_t numToInsert, void* thi } if (ALPHA_OR_BETA_VERSION && allocatedMemorySize < newMemorySize * elementSize) { - display->freezeWithError("FFFF"); + FREEZE_WITH_ERROR("FFFF"); } setMemory(newMemory, allocatedMemorySize); diff --git a/src/deluge/util/container/hashtable/open_addressing_hash_table.cpp b/src/deluge/util/container/hashtable/open_addressing_hash_table.cpp index df8ab76518..2cc986a488 100644 --- a/src/deluge/util/container/hashtable/open_addressing_hash_table.cpp +++ b/src/deluge/util/container/hashtable/open_addressing_hash_table.cpp @@ -88,7 +88,7 @@ void* OpenAddressingHashTable::insert(uint32_t key, bool* onlyIfNotAlreadyPresen #if ALPHA_OR_BETA_VERSION if (doesKeyIndicateEmptyBucket(key)) { - display->freezeWithError("E330"); + FREEZE_WITH_ERROR("E330"); } #endif @@ -197,7 +197,7 @@ void* OpenAddressingHashTable::lookup(uint32_t key) { #if ALPHA_OR_BETA_VERSION if (doesKeyIndicateEmptyBucket(key)) { - display->freezeWithError("E331"); + FREEZE_WITH_ERROR("E331"); } #endif @@ -238,7 +238,7 @@ bool OpenAddressingHashTable::remove(uint32_t key) { #if ALPHA_OR_BETA_VERSION if (doesKeyIndicateEmptyBucket(key)) { - display->freezeWithError("E332"); + FREEZE_WITH_ERROR("E332"); } #endif diff --git a/src/deluge/util/container/list/bidirectional_linked_list.cpp b/src/deluge/util/container/list/bidirectional_linked_list.cpp index 8a33baa138..9f7d2c1888 100644 --- a/src/deluge/util/container/list/bidirectional_linked_list.cpp +++ b/src/deluge/util/container/list/bidirectional_linked_list.cpp @@ -71,7 +71,7 @@ BidirectionalLinkedListNode* BidirectionalLinkedList::getNext(BidirectionalLinke void BidirectionalLinkedList::test() { if (first == NULL) { - display->freezeWithError("E005"); + FREEZE_WITH_ERROR("E005"); } int32_t count = 0; @@ -80,7 +80,7 @@ void BidirectionalLinkedList::test() { BidirectionalLinkedListNode** prevPointer = &first; while (true) { if (thisNode->prevPointer != prevPointer) { - display->freezeWithError("E006"); + FREEZE_WITH_ERROR("E006"); } if (thisNode == &endNode) { @@ -89,14 +89,14 @@ void BidirectionalLinkedList::test() { // Check the node references its list correctly if (thisNode->list != this) { - display->freezeWithError("E007"); + FREEZE_WITH_ERROR("E007"); } count++; // Check we're not spiralling around forever if (count > 2048) { - display->freezeWithError("E008"); + FREEZE_WITH_ERROR("E008"); } prevPointer = &thisNode->next; @@ -136,7 +136,7 @@ void BidirectionalLinkedListNode::insertOtherNodeBefore(BidirectionalLinkedListN if constexpr (ALPHA_OR_BETA_VERSION || kCurrentFirmwareVersion <= FIRMWARE_4P0P0) { // If we're not already in a list, that means we also don't have a valid prevPointer, so everything's about to break. This happened! if (!list) { - display->freezeWithError("E443"); + FREEZE_WITH_ERROR("E443"); } } otherNode->list = list; @@ -152,7 +152,7 @@ void BidirectionalLinkedListNode::insertOtherNodeBefore(BidirectionalLinkedListN bool BidirectionalLinkedListNode::isLast() { if constexpr (ALPHA_OR_BETA_VERSION || kCurrentFirmwareVersion <= FIRMWARE_4P0P0) { if (!list) { - display->freezeWithError("E444"); + FREEZE_WITH_ERROR("E444"); } } return (next == &list->endNode); diff --git a/src/deluge/util/d_string.cpp b/src/deluge/util/d_string.cpp index e2b5be867d..96939eee7e 100644 --- a/src/deluge/util/d_string.cpp +++ b/src/deluge/util/d_string.cpp @@ -137,12 +137,12 @@ void String::set(String* otherString) { //if the other string has memory and it's not in the non audio region if (sm) { if (!(EXTERNAL_MEMORY_END - RESERVED_EXTERNAL_ALLOCATOR < (uint32_t)sm && (uint32_t)sm < EXTERNAL_MEMORY_END)) { - display->freezeWithError("S001"); + FREEZE_WITH_ERROR("S001"); return; } //or if it doesn't have an allocation else if (!GeneralMemoryAllocator::get().getAllocatedSize(sm)) { - display->freezeWithError("S002"); + FREEZE_WITH_ERROR("S002"); return; } } diff --git a/src/deluge/version.h.in b/src/deluge/version.h.in index 9ed8c8b38e..540ce37f38 100644 --- a/src/deluge/version.h.in +++ b/src/deluge/version.h.in @@ -1,4 +1,6 @@ #pragma once + +#ifdef __cplusplus #include #include @@ -19,3 +21,14 @@ constexpr SemVer kCommunityFirmwareVersion { //clang-format on constexpr char const* kFirmwareVersionString = "@BUILD_VERSION_STRING@"; + +#else + +#define FIRMWARE_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ +#define FIRMWARE_VERSION_MINOR @PROJECT_VERSION_MINOR@ +#define FIRMWARE_VERSION_PATCH @PROJECT_VERSION_PATCH@ + +#define FIRMWARE_VERSION_STRING "@BUILD_VERSION_STRING@" +#define FIRMWARE_COMMIT_SHORT "@BUILD_COMMIT_SHORT@" + +#endif diff --git a/src/fault_handler.c b/src/fault_handler.c new file mode 100644 index 0000000000..07090e5b04 --- /dev/null +++ b/src/fault_handler.c @@ -0,0 +1,260 @@ +/******************************************************************************* + * DISCLAIMER + * This software is supplied by Renesas Electronics Corporation and is only + * intended for use with Renesas products. No other uses are authorized. This + * software is owned by Renesas Electronics Corporation and is protected under + * all applicable laws, including copyright laws. + * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING + * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT + * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. + * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS + * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE + * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR + * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE + * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * Renesas reserves the right, without notice, to make changes to this software + * and to discontinue the availability of this software. By using this software, + * you agree to the additional terms and conditions found by accessing the + * following link: + * http://www.renesas.com/disclaimer + * + * Copyright (C) 2014 Renesas Electronics Corporation. All rights reserved. + *******************************************************************************/ +/******************************************************************************* + * File Name : resetprg.c + * Device(s) : RZ/A1H (R7S721001) + * Tool-Chain : GNUARM-NONEv14.02-EABI + * H/W Platform : RSK+RZA1H CPU Board + * Description : Sample Program - C library entry point + * : Variants of this file must be created for each compiler + *******************************************************************************/ +/******************************************************************************* + * History : DD.MM.YYYY Version Description + * : 21.10.2014 1.00 + *******************************************************************************/ + +/* + * Copyright © 2021-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#include "fault_handler.h" +#include "RTT/SEGGER_RTT.h" +#include "RZA1/compiler/asm/inc/asm.h" +#include "RZA1/system/iodefines/dmac_iodefine.h" +#include "RZA1/uart/sio_char.h" +#include "definitions.h" +#include "drivers/uart/uart.h" +#include + +extern uint32_t program_stack_start; +extern uint32_t program_stack_end; +extern uint32_t program_code_start; +extern uint32_t program_code_end; + +[[gnu::always_inline]] inline void sendToPIC(uint8_t msg) { + intptr_t writePos = uartItems[UART_ITEM_PIC].txBufferWritePos; + volatile char* uncached_tx_buf = (volatile char*)(picTxBuffer + UNCACHED_MIRROR_OFFSET); + uncached_tx_buf[writePos] = msg; + uartItems[UART_ITEM_PIC].txBufferWritePos += 1; + uartItems[UART_ITEM_PIC].txBufferWritePos &= (PIC_TX_BUFFER_SIZE - 1); +} + +[[gnu::always_inline]] inline void sendColor(uint8_t r, uint8_t g, uint8_t b) { + sendToPIC(r); + sendToPIC(g); + sendToPIC(b); +} + +[[gnu::always_inline]] inline void drawByte(uint8_t byte, uint8_t r, uint8_t g, uint8_t b) { + for (int32_t idxBit = 7; idxBit >= 0; --idxBit) { + if (((byte >> idxBit) & 0x01) == 0x01) { + sendColor(r, g, b); + } + else { + sendColor(0, 0, 0); + } + } +} + +// Requires 32 pads so two double cloumns +[[gnu::always_inline]] inline int32_t drawPointer(uint32_t idxColumnPairStart, uint32_t pointerValue, uint8_t r, + uint8_t g, uint8_t b) { + sendToPIC(1 + idxColumnPairStart); + ++idxColumnPairStart; + + drawByte(pointerValue >> 24, r, g, b); + drawByte(pointerValue >> 16, r, g, b); + + sendToPIC(1 + idxColumnPairStart); + ++idxColumnPairStart; + + drawByte(pointerValue >> 8, r, g, b); + drawByte(pointerValue, r, g, b); + +#if ENABLE_TEXT_OUTPUT + SEGGER_RTT_printf(0, "PTR: 0x%8X (%d, %d, %d)\n", pointerValue, r, g, b); +#endif + + return idxColumnPairStart; +} + +[[gnu::always_inline]] inline bool isStackPointer(uint32_t value) { + if (value >= (uint32_t)&program_stack_start && value < (uint32_t)&program_stack_end) { + return true; + } + + return false; +} + +[[gnu::always_inline]] inline bool isCodePointer(uint32_t value) { + if (value >= (uint32_t)&program_code_start && value < (uint32_t)&program_code_end) { + return true; + } + + return false; +} + +[[gnu::always_inline]] inline uint8_t getHexCharValue(char input) { + uint8_t result = 0; + if (input >= '0' && input <= '9') { + result = input - '0'; + } + if (input >= 'a' && input <= 'f') { + result = input - 'a' + 10; + } + return result; +} + +#define MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MAX_POINTER_COUNT 4 +[[gnu::always_inline]] inline void printPointers(uint32_t addrSYSLR, uint32_t addrSYSSP, uint32_t addrUSRLR, + uint32_t addrUSRSP, bool hardFault) { + // Search for stack pointers + uint32_t stackPointer = 0; + if (isStackPointer(addrUSRSP)) { + stackPointer = addrUSRSP; + } + else if (isStackPointer(addrSYSSP)) { + stackPointer = addrSYSSP; + } + + uint8_t stackPointerCount = 0; + uint32_t stackPointers[MAX_POINTER_COUNT] = {0}; + + // Search for stack pointers before any printing + if (stackPointer != 0x00000000) { + stackPointer = stackPointer - (stackPointer % 4); // Align to 4 bytes + while (stackPointer <= (uint32_t)&program_stack_end) { + uint32_t stackValue = *((uint32_t*)stackPointer); + + // Print any pointer that is pointing to code, different from the LRs and not the same as before + if (isCodePointer(stackValue) && stackValue != stackPointers[MIN(0, stackPointerCount - 1)] + && stackValue != addrUSRLR && stackValue != addrSYSLR) { + stackPointers[stackPointerCount] = stackValue; + ++stackPointerCount; + + if (stackPointerCount >= MAX_POINTER_COUNT) { + break; + } + } + + stackPointer += 4; + } + } + + uint32_t currentColumnPairIndex = 0; + + // Print LR from USR mode if it is valid + if (isCodePointer(addrUSRLR)) { + currentColumnPairIndex = drawPointer(currentColumnPairIndex, addrUSRLR, 255, 0, 255); + } + + // Print LR from SYS mode if it is valid and different from USR mode + if (isCodePointer(addrSYSLR) && addrSYSLR != addrUSRLR) { + currentColumnPairIndex = drawPointer(currentColumnPairIndex, addrSYSLR, 0, 0, 255); + } + + // Print all pointers + if (stackPointerCount > 0) { + uint8_t currentPointerIndex = 0; + uint8_t currentBlueValue = 0; + while (currentPointerIndex < MAX_POINTER_COUNT) { + currentColumnPairIndex = + drawPointer(currentColumnPairIndex, stackPointers[currentPointerIndex], 0, 255, currentBlueValue); + + // Stop after filling all columns + if (currentColumnPairIndex >= 8) { + break; + } + + // Alternate colors + if (currentBlueValue == 0) { + currentBlueValue = 255; + } + else if (currentBlueValue == 255) { + currentBlueValue = 0; + } + + ++currentPointerIndex; + } + } + + // Clear all other pads + for (; currentColumnPairIndex < 8; ++currentColumnPairIndex) { + sendToPIC(1 + currentColumnPairIndex); + + for (uint32_t idxColumnPairBuffer = 0; idxColumnPairBuffer < 16; ++idxColumnPairBuffer) { + sendColor(0, 0, 0); + } + } + + // Print first 4 byte of commit ID + sendToPIC(1 + currentColumnPairIndex); + char commitShort[32] = FIRMWARE_COMMIT_SHORT; + + uint8_t firstByte = (getHexCharValue(commitShort[0]) << 4) | getHexCharValue(commitShort[1]); + drawByte(firstByte, 255, (hardFault ? 0 : 255), 0); + uint8_t secondByte = (getHexCharValue(commitShort[2]) << 4) | getHexCharValue(commitShort[3]); + drawByte(secondByte, 255, (hardFault ? 0 : 255), 0); + +#if ENABLE_TEXT_OUTPUT + SEGGER_RTT_printf(0, "COMMIT: %s\n", FIRMWARE_COMMIT_SHORT); +#endif + + uartFlushIfNotSending(UART_ITEM_PIC); + + // Wait for flush to finish + while (!(DMACn(PIC_TX_DMA_CHANNEL).CHSTAT_n & (1 << 6))) {} +} + +//@TODO: Pointers seem to be wrong right now and we will need to filter out the SP call to fault_handler_print_freeze_pointers (we can't inline, otherwise that would be huge) +extern void fault_handler_print_freeze_pointers(uint32_t addrSYSLR, uint32_t addrSYSSP, uint32_t addrUSRLR, + uint32_t addrUSRSP) { + __disable_irq(); + printPointers(addrSYSLR, addrSYSSP, addrUSRLR, addrUSRSP, false); + __enable_irq(); +} + +extern void handle_cpu_fault(uint32_t addrSYSLR, uint32_t addrSYSSP, uint32_t addrUSRLR, uint32_t addrUSRSP) { + printPointers(addrSYSLR, addrSYSSP, addrUSRLR, addrUSRSP, true); + + __asm__("CPS 0x10"); // Go to USR mode + + while (1) { + __asm__("nop"); + } +} diff --git a/src/fault_handler.h b/src/fault_handler.h new file mode 100644 index 0000000000..be1c982c92 --- /dev/null +++ b/src/fault_handler.h @@ -0,0 +1,68 @@ +/******************************************************************************* + * DISCLAIMER + * This software is supplied by Renesas Electronics Corporation and is only + * intended for use with Renesas products. No other uses are authorized. This + * software is owned by Renesas Electronics Corporation and is protected under + * all applicable laws, including copyright laws. + * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING + * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT + * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. + * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS + * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE + * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR + * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE + * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * Renesas reserves the right, without notice, to make changes to this software + * and to discontinue the availability of this software. By using this software, + * you agree to the additional terms and conditions found by accessing the + * following link: + * http://www.renesas.com/disclaimer + * + * Copyright (C) 2014 Renesas Electronics Corporation. All rights reserved. + *******************************************************************************/ +/******************************************************************************* + * File Name : resetprg.c + * Device(s) : RZ/A1H (R7S721001) + * Tool-Chain : GNUARM-NONEv14.02-EABI + * H/W Platform : RSK+RZA1H CPU Board + * Description : Sample Program - C library entry point + * : Variants of this file must be created for each compiler + *******************************************************************************/ +/******************************************************************************* + * History : DD.MM.YYYY Version Description + * : 21.10.2014 1.00 + *******************************************************************************/ + +/* + * Copyright © 2021-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void fault_handler_print_freeze_pointers(uint32_t addrSYSLR, uint32_t addrSYSSP, uint32_t addrUSRLR, + uint32_t addrUSRSP); +extern void handle_cpu_fault(uint32_t addrSYSLR, uint32_t addrSYSSP, uint32_t addrUSRLR, uint32_t addrUSRSP); + +#ifdef __cplusplus +} +#endif