diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f3a2fd78..7b41ef478 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,11 +16,13 @@ jobs: artifact-path: ${{ steps.upload64.outputs.artifact-path }} git_info: ${{ steps.gitinfo.outputs.git_info }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Compute Git Info for Artifact Name id: gitinfo - run: echo "::set-output name=git_info::$(date +%Y-%m-%d)-$(git rev-parse --short HEAD)" + run: echo "::set-output name=git_info::$(git log -1 --format=%cd --date=format:%y%m%d)-$(git rev-parse --short HEAD)" - name: Get specific commits of git submodules run: sh -ex ./submod.sh @@ -28,42 +30,38 @@ jobs: - name: Create sdcard directory run: mkdir -p ./sdcard/ - - name: Put git hash in startup message - run: | - sed -i "s/Loading.../$(date +%Y%m%d)-$(git rev-parse --short HEAD)/g" src/userinterface.cpp - # Install 64-bit toolchain (aarch64) - name: Install 64-bit toolchain run: | set -ex - wget -q https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz - tar xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz + wget -q https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf.tar.xz + tar xf arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf.tar.xz - name: Build for Raspberry Pi 5 (64-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=5 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Build for Raspberry Pi 4 (64-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=4 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Build for Raspberry Pi 3 (64-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=3 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Prepare SD card content for 64-bit run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH cd ./circle-stdlib/libs/circle/boot make make armstub64 @@ -76,6 +74,8 @@ jobs: # Performances git clone https://github.com/Banana71/Soundplantage --depth 1 cp -r ./Soundplantage/performance ./Soundplantage/*.pdf ./sdcard/ + cp -r ./performance/004_Mirage ./sdcard/performance/ + cp ./performance/*.pdf ./sdcard/ # Hardware configuration cd hwconfig sh -ex ./customize.sh @@ -93,7 +93,7 @@ jobs: id: upload64 uses: actions/upload-artifact@v4 with: - name: MiniDexed_${{ github.run_number }}_${{ steps.gitinfo.outputs.git_info }}_64bit + name: DreamDexed_${{ github.run_number }}_${{ steps.gitinfo.outputs.git_info }}_64bit path: sdcard/* build32: @@ -102,10 +102,12 @@ jobs: outputs: artifact-path: ${{ steps.upload32.outputs.artifact-path }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Compute Git Info for Artifact Name - run: echo "GIT_INFO=$(date +%Y-%m-%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + run: echo "GIT_INFO=$(git log -1 --format=%cd --date=format:%y%m%d)-$(git rev-parse --short HEAD)" >> $GITHUB_ENV - name: Get specific commits of git submodules run: sh -ex ./submod.sh @@ -113,28 +115,24 @@ jobs: - name: Create sdcard directory run: mkdir -p ./sdcard/ - - name: Put git hash in startup message - run: | - sed -i "s/Loading.../${{ env.GIT_INFO }}/g" src/userinterface.cpp - # Install 32-bit toolchain (arm-none-eabi) - name: Install 32-bit toolchain run: | set -ex - wget -q https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz - tar xf gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz + wget -q https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz + tar xf arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz - name: Build for Raspberry Pi 2 (32-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-arm-none-eabi/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=2 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ - name: Build for Raspberry Pi 1 (32-bit) run: | set -ex - export PATH=$(readlink -f ./gcc-arm-10.3-2021.07-x86_64-arm-none-eabi/bin):$PATH + export PATH=$(readlink -f ./arm-*/bin/):$PATH RPI=1 bash -ex build.sh cp ./src/kernel*.img ./sdcard/ @@ -142,7 +140,7 @@ jobs: id: upload32 uses: actions/upload-artifact@v4 with: - name: MiniDexed_${{ github.run_number }}_${{ env.GIT_INFO }}_32bit + name: DreamDexed_${{ github.run_number }}_${{ env.GIT_INFO }}_32bit path: sdcard/* combine: @@ -153,14 +151,14 @@ jobs: - name: Download artifacts uses: actions/download-artifact@v4 with: - pattern: MiniDexed_* + pattern: DreamDexed_* merge-multiple: true path: combined - name: Create combined ZIP file run: | cd combined - zip -r ../MiniDexed_${{ github.run_number }}_${{ needs.build64.outputs.git_info }}.zip . + zip -r ../DreamDexed_${{ github.run_number }}_${{ needs.build64.outputs.git_info }}.zip . cd .. - name: Upload to GitHub Releases (only when building from main branch) @@ -171,4 +169,4 @@ jobs: export UPLOADTOOL_PR_BODY="This is a continuous build. Feedback is appreciated." export UPLOADTOOL_BODY="This is a continuous build. Feedback is appreciated." wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh - bash ./upload.sh ./MiniDexed*.zip + bash ./upload.sh ./DreamDexed*.zip diff --git a/.gitignore b/.gitignore index 18989bd46..a60bf4581 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ # Toolchain gcc-* +arm-gnu-* # Build artifacts kernel* diff --git a/.gitmodules b/.gitmodules index 064ffe47b..f9dbe8367 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "CMSIS_5"] path = CMSIS_5 url = https://github.com/ARM-software/CMSIS_5 +[submodule "CloudSeedCore"] + path = CloudSeedCore + url = https://github.com/DreamDexed/CloudSeedCore diff --git a/CloudSeedCore b/CloudSeedCore new file mode 160000 index 000000000..11eb12568 --- /dev/null +++ b/CloudSeedCore @@ -0,0 +1 @@ +Subproject commit 11eb125687ccd73d89f01d16c255cc600dea68fe diff --git a/README.md b/README.md index cf33d173b..5d4909e1c 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,190 @@ -# MiniDexed ![Github Build Status](https://github.com/probonopd/MiniDexed/actions/workflows/build.yml/badge.svg) +# DreamDexed ![Github Build Status](https://github.com/DreamDexed/DreamDexed/actions/workflows/build.yml/badge.svg) + +DreamDexed is a [MiniDexed](https://github.com/probonopd/MiniDexed) fork with the following additional features: + +- [x] Configurable default screen +- [x] Support for MIDI controller encoders with relative mode +- [x] Noiseless performance and volume change +- [x] Configurable TG compressors +- [x] Master Compressor +- [x] 3-band EQ (per TG and Master) +- [x] TG-Link +- [x] Two Effect Sends with YKChrous, DreamDelay, PlateReverb, CloudSeed2 +- [ ] 8 channel mixer (Rpi4+) +- [ ] Multiple parts (RPi4+) +- [ ] Overlay Menu for easier parameter changes +- [ ] MIDI Controller DAW integration + +# DreamDexed Arturia fork + +This is a fork of DreamDexed that integrates better with Arturia keyboards. + +Maybe someday it will be part of the DreamDexed + +## Enabling + +This feature can be enabled in the minidexed.ini with: +``` +DAWControllerEnabled=1 +``` + +## Features + +### Controller Display, Main Encoder +The controller display in DAW mode shows the DreamDexed menu. + +With the main encoder you can navigate in the menu. + +The Home is the shift+Main click + +Supported: +- MiniLab 3 (tested) +- KeyLab mkII (tested) +- Keylab Essential +- Keylab Essential 3 + +### MiniLab 3 features: + +#### Encoders + +By holding down shift will bring up an overlay menu, where you can see and adjust what the encoders do. + +You can use the main encoder to select the current encoding page. + +Short pressing the shift will show the actual values. + +Holding down the shift will goes back to the normal menu. + +This overlay menu is context-aware, it is different if you are in the effect menu, or in a TG menu. + +If you are in a TG menu, it only affects the selected TG. + +If you are in the main menu, it affects the TGs on the first TG's channel. + +- Main Overlay 1 (default) + - Cutoff, Resonance, FX1Send, FX2Send + - PortamentoTime, Program, Volume, MasterVolume + - Faders: ChG 1 Vol, ChG 2 Vol, ChG 3 Vol, ChG 4 Vol + +- Effect Overlay 1 + - MasterEQLow, MasterEQMid, MasterEQHigh, MasterEQGain + - MasterEQLowMidFreq, MasterEQMidHighFreq, None, None + - Faders: MasterEQLow, MasterEQMid, MasterEQHigh, MasterEQGain + +- Effect Overlay 2 + - MasterCREnable, MasterCRPreGain, MasterCRAttack, MasterCRRelease + - MasterCRThresh, MasterCRRatio, MasterCRHPFilter, None + - Faders: MasterCRPreGain, MasterCRAttack, MasterCRRelease, MasterCRThresh + +- Main Overlay 2 + - Pan1, Pan2, Pan3, Pan4 + - Det1, Det2, Det3, Det4 + - Faders: TG1 Vol, TG2 Vol, TG3 Vol, TG4 Vol + +- Main Overlay 3 + - Pan5, Pan6, Pan7, Pan8 + - Det5, Det6, Det7, Det8 + - Faders: TG5 Vol, TG6 Vol, TG7 Vol, TG8 Vol + +- TG Overlay 1 + - Cutoff, Resonance, FX1Send, FX2Send + - MasterTune, PortamentoTime, Volume, Pan + - Faders: Cutoff, FX1Send, FX2Send, Volume + +- TG Overlay 2 + - MIDIChannel, Program, None, PitchBendRange + - PortamentoGlissando, MonoMode, None, PitchBendStep + +- TG Overlay 3 + - TGEQLow, TGEQMid, TGEQHigh, TGEQGain + - TGEQLowMidFreq, TGEQMidHighFreq, None, None + - Faders: TGEQLow, TGEQMid, TGEQHigh, TGEQGain + +- TG Overlay 4 + - CompressorEnable, CompressorPreGain, CompressorMakeupGain, None + - CompressorAttack, CompressorRelease, CompressorThresh, CompressorRatio + - Faders: CompressorPreGain, CompressorAttack, CompressorRelease, CompressorThresh + +- TG Overlay 5 + - MWRange, MWPitch, FCRange, FCPitch + - MWEGBias, MWAmplitude, FCEGBias, FCAmplitude + +- TG Overlay 6 + - BCRange, BCPitch, ATRange, ATPitch + - BCEGBias, BCAmplitude, ATEGBias, ATAmplitude + +- Voice Overlay 1 + - ALGORITHM, FEEDBACK, TRANSPOSE, None, + - None, None, None, None + +- Voice Overlay 2 + - PITCH_EG_R1, PITCH_EG_R2, PITCH_EG_R3, PITCH_EG_R4 + - PITCH_EG_L1, PITCH_EG_L2, PITCH_EG_L3, PITCH_EG_L4 + - Faders: PITCH_EG_L1, PITCH_EG_L2, PITCH_EG_L3, PITCH_EG_L4 + +- Voice Overlay 3 + - OSC_KEY_SYNC, LFO_SPEED, LFO_DELAY, LFO_PITCH_MOD_DEP + - LFO_SYNC, LFO_WAVE, LFO_PITCH_MOD_SENS, LFO_AMP_MOD_DEP + +- OP Overlay 1 + - OP_OUTPUT_LEV, OP_FREQ_COARSE, OP_FREQ_FINE, OP_OSC_DETUNE, + - OP_OSC_MODE, OP_ENABLE, None, None + +- OP Overlay 2 + - OP_EG_R1, OP_EG_R2, P_EG_R3, OP_EG_R4 + - OP_EG_L1, OP_EG_L2, OP_EG_L3, OP_EG_L4, + - Faders: OP_EG_L1, OP_EG_L2, OP_EG_L3, OP_EG_L4, + +- OP Overlay 3 + - OP_LEV_SCL_BRK_PT, OP_SCL_LEFT_DEPTH, OP_SCL_RGHT_DEPTH, OP_AMP_MOD_SENS + - OP_OSC_RATE_SCALE, OP_SCL_LEFT_CURVE, OP_SCL_RGHT_CURVE, OP_KEY_VEL_SENS + +In the Main overlay you can reach the TG and voice overlays also. + +In the voice overlay there is a page for every OP control also, with the 6 operator and with an encoder which sets all. + +#### Pads on Bank A +- Mono/Poly mode +- Portamento enable/disable, hard press to enable/disable Portamento Glissando +- Sostenuto +- Sustain +- All Sound Off +- Hold2 +- None +- Channel AfterTouch Pad + +#### Pads on Bank B +- Short press a TG will enable/disable that TG +- Long press will enable/disable all the TG on the TG's channel +- Hard press will enable only that TG (it uses the pad's AT messsages) + + +### KeyLab mkII features + +#### Faders +- The faders 1-8 adjust the volume of the MIDI channels of the current performance +- The fader 9 adjusts the master volume. + +#### Encoders +- Cutoff, Resonance, Portamento Time +- None, None, Dry Level, FX1 Send, FX2 Send, None + +#### DAW buttons +- Mono/Poly mode +- Portamento enable/disable, hard press to enable/disable Portamento Glissando +- Sostenuto +- Sustain +- Hold2 + +#### Track select buttons +- Short press a TG will enable/disable that TG +- Long press will enable only that TG + + ![minidexed](https://user-images.githubusercontent.com/2480569/161813414-bb156a1c-efec-44c0-802a-8926412a08e0.jpg) -MiniDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer running on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 tone generators, not unlike the TX816/TX802 (8 DX7 instances without the keyboard in one box). [Featured by HACKADAY](https://hackaday.com/2022/04/19/bare-metal-gives-this-pi-some-classic-synths/), [Adafruit](https://blog.adafruit.com/2022/04/25/free-yamaha-dx7-synth-emulator-on-a-raspberry-pi/), [The MagPi magazine](https://magpi.raspberrypi.com/articles/mini-dexed) (Issue 142 June 2024, [PDF](https://magpi.raspberrypi.com/issues/142)) and [Synth Geekery](https://www.youtube.com/watch?v=TDSy5nnm0jA). +DreamDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known Japanese manufacturer running on a bare metal Raspberry Pi (without a Linux kernel or operating system). On Raspberry Pi 2 and larger, it can run 8 tone generators, not unlike the TX816/TX802 (8 DX7 instances without the keyboard in one box). [Featured by HACKADAY](https://hackaday.com/2022/04/19/bare-metal-gives-this-pi-some-classic-synths/), [Adafruit](https://blog.adafruit.com/2022/04/25/free-yamaha-dx7-synth-emulator-on-a-raspberry-pi/), [The MagPi magazine](https://magpi.raspberrypi.com/articles/mini-dexed) (Issue 142 June 2024, [PDF](https://magpi.raspberrypi.com/issues/142)) and [Synth Geekery](https://www.youtube.com/watch?v=TDSy5nnm0jA). ## Demo songs @@ -13,7 +195,7 @@ Listen to some examples made with MiniDexed by Banana71 [here](https://soundclou - [x] Uses [Synth_Dexed](https://codeberg.org/dcoredump/Synth_Dexed) with [circle-stdlib](https://github.com/smuehlst/circle-stdlib) - [x] SD card contents can be downloaded from [GitHub Releases](../../releases) - [x] Runs on all Raspberry Pi models (except Pico); see below for details -- [x] Produces sound on the headphone jack, HDMI display or [audio extractor](https://github.com/probonopd/MiniDexed/wiki/Hardware#hdmi-to-audio) (better), or a [dedicated DAC](https://github.com/probonopd/MiniDexed/wiki/Hardware#i2s-dac) (best) +- [x] Produces sound on the headphone jack, HDMI display or [audio extractor](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#hdmi-to-audio) (better), or a [dedicated DAC](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#i2s-dac) (best) - [x] Supports multiple voices through Program Change and Bank Change LSB/MSB MIDI messages - [x] Loads voices from `.syx` files from SD card (e.g., using `getsysex.sh` or from [Dexed_cart_1.0.zip](http://hsjp.eu/downloads/Dexed/Dexed_cart_1.0.zip)) - [x] Menu structure on optional [HD44780 display](https://www.berrybase.de/sensoren-module/displays/alphanumerische-displays/alphanumerisches-lcd-16x2-gr-252-n/gelb) and rotary encoder @@ -22,7 +204,7 @@ Listen to some examples made with MiniDexed by Banana71 [here](https://soundclou - [x] Allows to configure multiple Dexed instances through `performance.ini` files (e.g., [converted](https://github.com/BobanSpasic/MDX_Vault) from DX1, DX5, TX816, DX7II, TX802) - [x] Compressor effect - [x] Reverb effect -- [x] Voices can be edited over MIDI, e.g., using the [synthmata](https://synthmata.github.io/volca-fm/) online editor (requires [additional hardware](https://github.com/probonopd/MiniDexed/wiki/Hardware#usb-midi-devices)) +- [x] Voices can be edited over MIDI, e.g., using the [synthmata](https://synthmata.github.io/volca-fm/) online editor (requires [additional hardware](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#usb-midi-devices)) ## Introduction @@ -33,8 +215,8 @@ Video about this project by [Floyd Steinberg](https://www.youtube.com/watch?v=Z3 ## System Requirements - Raspberry Pi 1, 2, 3, 4, or 400. Raspberry Pi Zero and Zero 2 can be used but need HDMI or a supported i2s DAC for audio out. On Raspberry Pi 1 and on Raspberry Pi Zero there will be severely limited functionality (only one tone generator instead of 8) -- Raspberry Pi 5 can be used but currently support is experimental: HDMI sound and USB Gadget mode are not available yet, and it is not clear if there are implications for cooling from running MiniDexed. Also, MiniDexed is currently not taking advantage of the higher processing power of the Raspberry Pi 5 yet. *Hence, you may consider using one of the less expensive, older Raspberry Pi boards for your first build.* -- A [PCM5102A or PCM5122 based DAC](https://github.com/probonopd/MiniDexed/wiki/Hardware#i2s-dac), HDMI display or [audio extractor](https://github.com/probonopd/MiniDexed/wiki/Hardware#hdmi-to-audio) for good sound quality. If you don't have this, you can use the headphone jack on the Raspberry Pi but on anything but the Raspberry 4 the sound quality will be seriously limited +- Raspberry Pi 5 can be used but currently support is experimental: HDMI sound and USB Gadget mode are not available yet, and it is not clear if there are implications for cooling from running DreamDexed. Also, DreamDexed is currently not taking advantage of the higher processing power of the Raspberry Pi 5 yet. *Hence, you may consider using one of the less expensive, older Raspberry Pi boards for your first build.* +- A [PCM5102A or PCM5122 based DAC](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#i2s-dac), HDMI display or [audio extractor](https://github.com/DreamDexed/DreamDexed/wiki/Hardware#hdmi-to-audio) for good sound quality. If you don't have this, you can use the headphone jack on the Raspberry Pi but on anything but the Raspberry 4 the sound quality will be seriously limited - Optionally (but highly recommended), an [LCDC1602 Display](https://www.berrybase.de/en/sensors-modules/displays/alphanumeric-displays/alphanumerisches-lcd-16x2-gr-252-n/gelb) (with or without i2c "backpack" board) and a [KY-040 rotary encoder](https://www.berrybase.de/en/components/passive-components/potentiometer/rotary-encoder/drehregler/rotary-encoder-mit-breakoutboard-ohne-gewinde-und-mutter) ## Usage @@ -53,10 +235,10 @@ Video about this project by [Floyd Steinberg](https://www.youtube.com/watch?v=Z3 - Start playing - If the system seems to become unresponsive after a few seconds, remove `usbspeed=full` from `cmdline.txt` and repeat ([details](https://github.com/probonopd/MiniDexed/issues/39)) - Optionally, put voices in `.syx` files onto the SD card (e.g., using `getsysex.sh`) -- See the Wiki for [Menu](https://github.com/probonopd/MiniDexed/wiki/Menu) operation +- See the Wiki for [Menu](https://github.com/DreamDexed/DreamDexed/wiki/Menu) operation - For voice programming, use any DX series editor (using MIDI sysex), including Dexed - For library management, use the dedicated [MiniDexedLibrarian](https://github.com/BobanSpasic/MiniDexedLibrarian) software -- If something is unclear or does not work, don't hesitate to [ask](https://github.com/probonopd/MiniDexed/discussions/)! +- If something is unclear or does not work, don't hesitate to [ask](https://github.com/DreamDexed/DreamDexed/discussions/)! ## Pinout @@ -64,7 +246,7 @@ All devices on Raspberry Pi GPIOs are **optional**. ![Raspberry Pi Pinout/GPIO Diagram](https://user-images.githubusercontent.com/2480569/166105580-da11481c-8fc7-4375-8ab1-3031ab5c6ad0.png) -Please see the [wiki](https://github.com/probonopd/MiniDexed/wiki) for more information. +Please see the [wiki](https://github.com/DreamDexed/DreamDexed/wiki) for more information. ## Downloading @@ -72,19 +254,19 @@ Compiled versions are available on [GitHub Releases](../../releases). Just downl ## Building -Please see the [wiki](https://github.com/probonopd/MiniDexed/wiki/Development#building-locally) on how to compile the code yourself. +Please see the [wiki](https://github.com/DreamDexed/DreamDexed/wiki/Development#building-locally) on how to compile the code yourself. ## Contributing -This project lives from the contributions of skilled C++ developers, testers, writers, etc. Please see . +This project lives from the contributions of skilled C++ developers, testers, writers, etc. Please see . ## Discussions -We are happy to hear from you. Please join the discussions on . +We are happy to hear from you. Please join the discussions on . ## Documentation -Project documentation is at . +Project documentation is at . ## Acknowledgements @@ -93,14 +275,25 @@ This project stands on the shoulders of giants. Special thanks to: - [raphlinus](https://github.com/raphlinus) for the [MSFA](https://github.com/google/music-synthesizer-for-android) sound engine - [asb2m10](https://github.com/asb2m10/dexed) for the [Dexed](https://github.com/asb2m10/dexed) software - [dcoredump](https://github.com/dcoredump) for [Synth Dexed](https://codeberg.org/dcoredump/Synth_Dexed), a port of Dexed for embedded systems -- [rsta2](https://github.com/rsta2) for [Circle](https://github.com/rsta2/circle), the library to run code on bare metal Raspberry Pi (without a Linux kernel or operating system) and for the bulk of the MiniDexed code +- [rsta2](https://github.com/rsta2) for [Circle](https://github.com/rsta2/circle), the library to run code on bare metal Raspberry Pi (without a Linux kernel or operating system) and for the bulk of the DreamDexed code - [smuehlst](https://github.com/smuehlst) for [circle-stdlib](https://github.com/smuehlst/circle-stdlib), a version with Standard C and C++ library support -- [Banana71](https://github.com/Banana71) for the sound design of the [Soundplantage](https://github.com/Banana71/Soundplantage) performances shipped with MiniDexed +- [Banana71](https://github.com/Banana71) for the sound design of the [Soundplantage](https://github.com/Banana71/Soundplantage) performances shipped with DreamDexed - [BobanSpasic](https://github.com/BobanSpasic) for the [MiniDexedLibrarian](https://github.com/BobanSpasic/MiniDexedLibrarian) software, [MiniDexed performance converter](https://github.com/BobanSpasic/MDX_PerfConv) and [collection of performances for MiniDexed](https://github.com/BobanSpasic/MDX_Vault) -- [diyelectromusic](https://github.com/diyelectromusic/) for many [contributions](https://github.com/probonopd/MiniDexed/commits?author=diyelectromusic) +- [diyelectromusic](https://github.com/diyelectromusic/) for many [contributions](https://github.com/DreamDexed/DreamDexed/commits?author=diyelectromusic) - [dwhinham/mt32-pi](https://github.com/dwhinham/mt32-pi) for creating networking support for Circle - [omersiar](https://github.com/omersiar) for porting networking support to MiniDexed - [soyersoyer](https://github.com/soyersoyer) for sound and other improvements, and for debugging + +## About the Reverb (Cloud Seed) + +DreamDexed includes the **Cloud Seed** reverb algorithm, originally created by [Ghost Note Audio](https://github.com/ValdemarOrn/CloudSeed). + +- The algorithm is MIT-licensed and may be used in both free and commercial projects. +- **Cloud Seed** is the work of Ghost Note Audio and not part of DreamDexed itself. +- When mentioning *Cloud Seed* in documentation or marketing, it must be clear that DreamDexed is an independent project that simply makes use of this reverb algorithm. +- Ghost Note Audio reserves the right to withdraw the use of the *Cloud Seed* name if these conditions are not respected. -## Stargazers over time -[![Stargazers over time](https://starchart.cc/probonopd/MiniDexed.svg?variant=adaptive)](https://starchart.cc/probonopd/MiniDexed) +### Credits +A huge thanks to **Ghost Note Audio** for releasing this gem under MIT. +Without Cloud Seed, our DX tones would be stuck in the dry desert of 80s presets โ€” +now they can float through infinite digital cathedrals. ๐ŸŒŒ๐ŸŽนโœจ diff --git a/Synth_Dexed b/Synth_Dexed index 8c677ceb4..e3f524c8b 160000 --- a/Synth_Dexed +++ b/Synth_Dexed @@ -1 +1 @@ -Subproject commit 8c677ceb4b3fb73f8643e30ff6cf4158dc8b9e53 +Subproject commit e3f524c8bd92cdd37d0aea2728ea991254dda8ab diff --git a/circle-stdlib b/circle-stdlib index 61cf3a47b..83efe0b46 160000 --- a/circle-stdlib +++ b/circle-stdlib @@ -1 +1 @@ -Subproject commit 61cf3a47bf93628039078b7c840e44432e52343e +Subproject commit 83efe0b460555910878476fdcdbccbc185c92408 diff --git a/performance/004_Mirage/000001_Ambient-DDx.ini b/performance/004_Mirage/000001_Ambient-DDx.ini new file mode 100644 index 000000000..bbb80607e --- /dev/null +++ b/performance/004_Mirage/000001_Ambient-DDx.ini @@ -0,0 +1,408 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=40 +Pan1=0 +Detune1=-5 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=0 +EQMid1=0 +EQHigh1=0 +EQGain1=0 +EQLowMidFreq1=21 +EQMidHighFreq1=49 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=40 +Pan2=127 +Detune2=5 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=0 +EQMid2=0 +EQHigh2=0 +EQGain2=0 +EQLowMidFreq2=21 +EQMidHighFreq2=49 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=40 +Pan3=0 +Detune3=-3 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=21 +EQMidHighFreq3=49 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=40 +Pan4=127 +Detune4=3 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=21 +EQMidHighFreq4=49 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=1 +Volume5=40 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode5=0 +TGLink5=1 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=21 +EQMidHighFreq5=49 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=1 +Volume6=40 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode6=0 +TGLink6=1 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=21 +EQMidHighFreq6=49 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=1 +Volume7=40 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode7=0 +TGLink7=1 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=21 +EQMidHighFreq7=49 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=1 +Volume8=40 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 08 63 63 63 00 00 00 00 00 00 00 00 00 54 00 05 00 07 0F 63 0C 10 5E 63 58 00 00 00 00 00 00 00 00 00 3B 00 08 00 07 63 63 63 25 63 63 63 00 00 00 00 00 00 00 00 03 4A 01 00 18 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 5E 00 01 00 07 19 16 08 1E 5D 63 5F 00 00 00 00 00 00 00 00 01 4D 00 01 00 07 1E 1F 0D 1F 63 5C 40 00 00 00 00 00 00 00 00 00 63 00 01 00 07 55 63 63 05 32 32 32 00 01 07 00 0A 61 40 00 00 04 01 18 41 6D 62 44 44 78 20 20 20 20 00 +MonoMode8=0 +TGLink8=1 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=21 +EQMidHighFreq8=49 +SendFX1Slot1=None +SendFX1Slot2=DreamDelay +SendFX1Slot3=CloudSeed2 +SendFX1DreamDelayMix=54 +SendFX1DreamDelayMode=1 +SendFX1DreamDelayTime=107 +SendFX1DreamDelayTimeL=105 +SendFX1DreamDelayTimeR=107 +SendFX1DreamDelayTempo=30 +SendFX1DreamDelayFeedback=35 +SendFX1DreamDelayHighCut=50 +SendFX1DreamDelayBypass=0 +SendFX1CloudSeed2Preset=FXDivineInspiration +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=123 +SendFX1CloudSeed2EarlyOut=122 +SendFX1CloudSeed2LateOut=108 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=8 +SendFX1CloudSeed2EarlyDiffuseDelay=93 +SendFX1CloudSeed2EarlyDiffuseModAmount=31 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=12 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=4 +SendFX1CloudSeed2LateLineSize=87 +SendFX1CloudSeed2LateLineModAmount=95 +SendFX1CloudSeed2LateDiffuseDelay=79 +SendFX1CloudSeed2LateDiffuseModAmount=58 +SendFX1CloudSeed2LateLineDecay=86 +SendFX1CloudSeed2LateLineModRate=79 +SendFX1CloudSeed2LateDiffuseFeedback=80 +SendFX1CloudSeed2LateDiffuseModRate=41 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=1 +SendFX1CloudSeed2EqLowFreq=49 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=70 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=None +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000002_Pop Ballad.ini b/performance/004_Mirage/000002_Pop Ballad.ini new file mode 100644 index 000000000..5f2410b23 --- /dev/null +++ b/performance/004_Mirage/000002_Pop Ballad.ini @@ -0,0 +1,420 @@ +BankNumber1=0 +VoiceNumber1=15 +MIDIChannel1=1 +Volume1=48 +Pan1=0 +Detune1=2 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=43 0B 0B 2A 63 58 00 00 27 06 1E 03 00 06 00 00 42 00 05 00 0E 45 0A 0D 2A 63 58 00 00 22 08 09 00 00 01 00 04 4E 00 01 00 0A 4E 49 33 37 63 3A 00 00 33 0C 0B 03 03 01 00 02 59 01 06 1B 06 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 03 63 00 01 00 08 42 0B 00 27 63 4F 00 00 26 0D 09 00 00 03 00 01 4C 00 01 01 00 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 02 63 00 01 00 03 63 63 63 63 32 32 32 32 08 07 01 23 00 00 00 01 00 00 18 6D 44 78 43 50 62 72 69 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=0 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=-12 +EQMid1=0 +EQHigh1=0 +EQGain1=0 +EQLowMidFreq1=12 +EQMidHighFreq1=44 +BankNumber2=0 +VoiceNumber2=15 +MIDIChannel2=1 +Volume2=48 +Pan2=127 +Detune2=0 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=43 0B 0B 2A 63 58 00 00 27 06 1E 03 00 06 00 00 44 00 05 00 0E 45 0A 0D 2A 63 58 00 00 22 08 09 00 00 01 00 04 4E 00 01 00 0A 4E 49 33 37 63 3A 00 00 33 0C 0B 03 03 01 00 02 59 01 06 1C 06 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 03 63 00 01 00 08 42 0B 00 27 63 4F 00 00 26 0D 09 00 00 03 00 01 4C 00 01 01 00 40 15 07 2C 63 4F 00 00 1E 00 00 00 00 07 00 02 63 00 01 00 03 63 63 63 63 32 32 32 32 08 07 01 23 00 00 00 01 00 00 18 6D 44 78 43 50 62 72 69 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=0 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=-12 +EQMid2=0 +EQHigh2=0 +EQGain2=0 +EQLowMidFreq2=12 +EQMidHighFreq2=44 +BankNumber3=0 +VoiceNumber3=4 +MIDIChannel3=1 +Volume3=48 +Pan3=0 +Detune3=-2 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=63 22 1B 27 63 51 00 00 15 00 46 00 01 04 00 04 54 00 05 00 08 5D 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 01 4C 00 01 00 06 50 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 1C 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4F 00 05 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 02 03 00 23 00 00 00 01 03 00 18 50 49 41 4E 4F 20 43 50 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=0 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=-12 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=12 +EQMidHighFreq3=44 +BankNumber4=0 +VoiceNumber4=4 +MIDIChannel4=1 +Volume4=48 +Pan4=127 +Detune4=1 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 22 1B 27 63 51 00 00 15 00 46 00 01 04 00 04 54 00 05 00 08 5D 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 01 4C 00 01 00 06 50 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 1C 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4F 00 05 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 02 03 00 23 00 00 00 01 03 00 18 50 49 41 4E 4F 20 43 50 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=0 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=-12 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=12 +EQMidHighFreq4=44 +BankNumber5=0 +VoiceNumber5=4 +MIDIChannel5=0 +Volume5=71 +Pan5=64 +Detune5=0 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 22 1B 27 63 51 00 00 15 00 46 00 01 04 00 04 53 00 05 00 08 5D 45 0A 2F 63 61 00 00 09 00 63 00 01 05 00 01 52 00 01 00 06 50 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 1C 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4F 00 05 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 03 01 00 23 00 00 00 01 03 00 18 50 49 41 4E 4F 20 44 55 4F 53 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=1 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=-12 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=12 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=4 +MIDIChannel6=1 +Volume6=72 +Pan6=63 +Detune6=4 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=4F 2B 24 2D 63 45 00 00 15 00 2C 00 01 04 00 06 4F 00 05 00 08 5F 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 01 4C 00 01 00 06 5F 0E 0D 28 63 5B 00 00 0F 24 1E 01 01 07 00 03 63 00 01 00 07 5F 22 1B 2F 63 5A 00 00 05 00 63 00 01 02 00 03 4E 00 07 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 58 00 01 00 09 58 1C 1B 32 63 5A 00 00 31 20 5F 01 02 02 00 04 63 00 01 00 07 00 00 00 00 32 32 32 32 02 05 00 23 00 00 00 01 03 00 18 3E 50 49 41 4E 4F 20 43 50 20 00 +MonoMode6=0 +TGLink6=1 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=-12 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=12 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=100 +Pan7=64 +Detune7=-1 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=99 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=52 5F 12 30 58 63 00 00 18 00 0E 00 00 03 00 02 4F 00 03 00 07 5C 63 1F 37 63 63 00 00 18 0C 00 03 00 03 00 02 4A 00 01 00 07 52 35 17 35 63 5A 00 00 27 00 00 00 00 04 02 02 5A 00 01 00 07 52 5F 1F 2D 53 63 00 00 18 00 09 00 00 00 00 04 4C 00 03 00 07 63 63 19 37 63 63 00 00 27 00 00 00 00 03 00 07 43 00 01 00 07 52 32 14 38 63 5A 00 00 27 00 00 00 00 04 02 02 63 00 01 00 07 63 63 63 63 32 32 32 32 02 06 01 13 2F 00 00 01 00 03 18 31 39 38 32 20 20 20 20 20 20 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=1 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=100 +Pan8=64 +Detune8=0 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=99 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=52 5F 12 30 58 63 00 00 18 00 0E 00 00 03 00 02 4F 00 03 00 07 5C 63 1F 37 63 63 00 00 18 0C 00 03 00 03 00 02 4A 00 01 00 07 52 35 17 35 63 5A 00 00 27 00 00 00 00 04 02 02 5A 00 01 00 07 52 5F 1F 2D 53 63 00 00 18 00 09 00 00 00 00 04 4C 00 03 00 07 63 63 19 37 63 63 00 00 27 00 00 00 00 03 00 07 43 00 01 00 07 52 32 14 38 63 5A 00 00 27 00 00 00 00 04 02 02 63 00 01 00 07 63 63 63 63 32 32 32 32 02 06 01 13 2F 00 00 01 00 03 18 31 39 38 32 20 20 20 20 20 20 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=1 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=CloudSeed2 +SendFX1Slot3=None +SendFX1YKChorusMix=16 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=20 +SendFX1YKChorusLFORate2=35 +SendFX1YKChorusBypass=0 +SendFX1CloudSeed2Preset=LBigSoundStage +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=127 +SendFX1CloudSeed2EarlyOut=0 +SendFX1CloudSeed2LateOut=69 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=5 +SendFX1CloudSeed2EarlyDiffuseDelay=88 +SendFX1CloudSeed2EarlyDiffuseModAmount=43 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=44 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=7 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=8 +SendFX1CloudSeed2LateLineSize=31 +SendFX1CloudSeed2LateLineModAmount=0 +SendFX1CloudSeed2LateDiffuseDelay=22 +SendFX1CloudSeed2LateDiffuseModAmount=24 +SendFX1CloudSeed2LateLineDecay=20 +SendFX1CloudSeed2LateLineModRate=0 +SendFX1CloudSeed2LateDiffuseFeedback=112 +SendFX1CloudSeed2LateDiffuseModRate=32 +SendFX1CloudSeed2EqLowShelfEnabled=1 +SendFX1CloudSeed2EqHighShelfEnabled=1 +SendFX1CloudSeed2EqLowpassEnabled=0 +SendFX1CloudSeed2EqLowFreq=33 +SendFX1CloudSeed2EqHighFreq=55 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=123 +SendFX1CloudSeed2EqHighGain=59 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=EQ +MasterFXSlot2=Compressor +MasterFXSlot3=None +MasterFXEQLow=-1 +MasterFXEQMid=3 +MasterFXEQHigh=0 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=25 +MasterFXEQMidHighFreq=46 +MasterFXEQBypass=0 +MasterFXCompressorPreGain=2 +MasterFXCompressorThresh=-14 +MasterFXCompressorRatio=3 +MasterFXCompressorAttack=50 +MasterFXCompressorRelease=250 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000003_MagicOrgan.ini b/performance/004_Mirage/000003_MagicOrgan.ini new file mode 100644 index 000000000..1aa716435 --- /dev/null +++ b/performance/004_Mirage/000003_MagicOrgan.ini @@ -0,0 +1,414 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=75 +Pan1=64 +Detune1=0 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=0 +FX2Send1=99 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=08 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 55 00 10 00 07 0D 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 57 00 0C 00 07 06 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 53 00 08 00 07 0D 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 62 00 10 00 07 12 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 0C 00 07 63 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 08 00 07 63 63 63 63 32 32 32 32 1F 00 00 23 00 06 00 01 00 01 18 42 69 6E 67 65 6C 20 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=1 +CompressorPreGain1=10 +CompressorThresh1=-44 +CompressorRatio1=5 +CompressorAttack1=65 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=-6 +EQMid1=0 +EQHigh1=7 +EQGain1=0 +EQLowMidFreq1=24 +EQMidHighFreq1=47 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=100 +Pan2=0 +Detune2=-5 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode2=0 +TGLink2=2 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=1 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=2 +EQMid2=0 +EQHigh2=5 +EQGain2=0 +EQLowMidFreq2=24 +EQMidHighFreq2=50 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=100 +Pan3=127 +Detune3=5 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode3=0 +TGLink3=2 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=1 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=2 +EQMid3=0 +EQHigh3=5 +EQGain3=0 +EQLowMidFreq3=24 +EQMidHighFreq3=50 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=0 +Volume4=48 +Pan4=63 +Detune4=0 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=99 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode4=0 +TGLink4=0 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=1 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=24 +EQMidHighFreq4=44 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=48 +Pan5=64 +Detune5=0 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=99 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=1 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=48 +Pan6=63 +Detune6=0 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=99 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=1 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=48 +Pan7=64 +Detune7=0 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=99 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=1 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=48 +Pan8=63 +Detune8=0 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=99 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=1 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=None +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=31 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=38 +SendFX1YKChorusLFORate2=64 +SendFX1YKChorusBypass=0 +SendFX1CloudSeed2Preset=LBigSoundStage +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=125 +SendFX1CloudSeed2EarlyOut=100 +SendFX1CloudSeed2LateOut=104 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=121 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=5 +SendFX1CloudSeed2EarlyDiffuseDelay=88 +SendFX1CloudSeed2EarlyDiffuseModAmount=43 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=44 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=7 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=8 +SendFX1CloudSeed2LateLineSize=31 +SendFX1CloudSeed2LateLineModAmount=0 +SendFX1CloudSeed2LateDiffuseDelay=22 +SendFX1CloudSeed2LateDiffuseModAmount=16 +SendFX1CloudSeed2LateLineDecay=46 +SendFX1CloudSeed2LateLineModRate=0 +SendFX1CloudSeed2LateDiffuseFeedback=112 +SendFX1CloudSeed2LateDiffuseModRate=32 +SendFX1CloudSeed2EqLowShelfEnabled=1 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=0 +SendFX1CloudSeed2EqLowFreq=33 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=123 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=DreamDelay +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2DreamDelayMix=48 +SendFX2DreamDelayMode=2 +SendFX2DreamDelayTime=28 +SendFX2DreamDelayTimeL=28 +SendFX2DreamDelayTimeR=19 +SendFX2DreamDelayTempo=120 +SendFX2DreamDelayFeedback=47 +SendFX2DreamDelayHighCut=50 +SendFX2DreamDelayBypass=0 +SendFX2ReturnLevel=99 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=None +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000004_Security.ini b/performance/004_Mirage/000004_Security.ini new file mode 100644 index 000000000..c568acb28 --- /dev/null +++ b/performance/004_Mirage/000004_Security.ini @@ -0,0 +1,429 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=90 +Pan1=0 +Detune1=-1 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=6 +CompressorThresh1=-16 +CompressorRatio1=2 +CompressorAttack1=35 +CompressorRelease1=165 +CompressorMakeupGain1=0 +EQLow1=-1 +EQMid1=1 +EQHigh1=6 +EQGain1=-1 +EQLowMidFreq1=22 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=90 +Pan2=127 +Detune2=1 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=6 +CompressorThresh2=-16 +CompressorRatio2=2 +CompressorAttack2=35 +CompressorRelease2=165 +CompressorMakeupGain2=0 +EQLow2=-1 +EQMid2=1 +EQHigh2=6 +EQGain2=-1 +EQLowMidFreq2=22 +EQMidHighFreq2=46 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=90 +Pan3=0 +Detune3=0 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=6 +CompressorThresh3=-16 +CompressorRatio3=2 +CompressorAttack3=35 +CompressorRelease3=165 +CompressorMakeupGain3=0 +EQLow3=-1 +EQMid3=1 +EQHigh3=6 +EQGain3=-1 +EQLowMidFreq3=22 +EQMidHighFreq3=46 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=90 +Pan4=127 +Detune4=-4 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4C 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 55 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 49 01 02 0E 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 61 00 01 00 07 5B 2D 1D 32 63 5F 00 00 03 00 17 00 01 03 00 07 4E 00 01 01 02 57 3D 1A 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 5C 00 01 00 07 63 63 63 63 32 32 32 32 08 06 00 0C 00 2E 00 00 00 01 18 53 65 63 75 72 69 74 79 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=6 +CompressorThresh4=-16 +CompressorRatio4=2 +CompressorAttack4=35 +CompressorRelease4=165 +CompressorMakeupGain4=0 +EQLow4=-1 +EQMid4=1 +EQHigh4=6 +EQGain4=-1 +EQLowMidFreq4=22 +EQMidHighFreq4=46 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=56 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=99 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=1 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=56 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=99 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=15 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=56 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=99 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=56 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=99 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=DreamDelay +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=10 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=46 +SendFX1YKChorusLFORate2=73 +SendFX1YKChorusBypass=0 +SendFX1DreamDelayMix=11 +SendFX1DreamDelayMode=1 +SendFX1DreamDelayTime=1 +SendFX1DreamDelayTimeL=1 +SendFX1DreamDelayTimeR=2 +SendFX1DreamDelayTempo=120 +SendFX1DreamDelayFeedback=1 +SendFX1DreamDelayHighCut=57 +SendFX1DreamDelayBypass=0 +SendFX1CloudSeed2Preset=FXDivineInspiration +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=127 +SendFX1CloudSeed2EarlyOut=0 +SendFX1CloudSeed2LateOut=64 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=91 +SendFX1CloudSeed2TapDecay=0 +SendFX1CloudSeed2TapPredelay=12 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=6 +SendFX1CloudSeed2EarlyDiffuseDelay=67 +SendFX1CloudSeed2EarlyDiffuseModAmount=0 +SendFX1CloudSeed2EarlyDiffuseFeedback=35 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=8 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=8 +SendFX1CloudSeed2LateLineSize=0 +SendFX1CloudSeed2LateLineModAmount=64 +SendFX1CloudSeed2LateDiffuseDelay=80 +SendFX1CloudSeed2LateDiffuseModAmount=28 +SendFX1CloudSeed2LateLineDecay=8 +SendFX1CloudSeed2LateLineModRate=47 +SendFX1CloudSeed2LateDiffuseFeedback=99 +SendFX1CloudSeed2LateDiffuseModRate=44 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=1 +SendFX1CloudSeed2EqLowFreq=49 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=103 +SendFX1CloudSeed2EqLowGain=70 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=EQ +MasterFXSlot3=Compressor +MasterFXEQLow=0 +MasterFXEQMid=0 +MasterFXEQHigh=4 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=22 +MasterFXEQMidHighFreq=51 +MasterFXEQBypass=0 +MasterFXCompressorPreGain=2 +MasterFXCompressorThresh=-15 +MasterFXCompressorRatio=3 +MasterFXCompressorAttack=45 +MasterFXCompressorRelease=230 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000005_SomniumDyna.ini b/performance/004_Mirage/000005_SomniumDyna.ini new file mode 100644 index 000000000..56317954a --- /dev/null +++ b/performance/004_Mirage/000005_SomniumDyna.ini @@ -0,0 +1,412 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=42 +Pan1=0 +Detune1=-5 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=0 +EQMid1=0 +EQHigh1=0 +EQGain1=0 +EQLowMidFreq1=21 +EQMidHighFreq1=49 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=42 +Pan2=127 +Detune2=5 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=0 +EQMid2=0 +EQHigh2=0 +EQGain2=0 +EQLowMidFreq2=21 +EQMidHighFreq2=49 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=42 +Pan3=0 +Detune3=-3 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=21 +EQMidHighFreq3=49 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=42 +Pan4=127 +Detune4=3 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=21 +EQMidHighFreq4=49 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=1 +Volume5=42 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode5=0 +TGLink5=1 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=21 +EQMidHighFreq5=49 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=1 +Volume6=42 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode6=0 +TGLink6=1 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=21 +EQMidHighFreq6=49 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=1 +Volume7=42 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode7=0 +TGLink7=1 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=21 +EQMidHighFreq7=49 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=1 +Volume8=42 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=2E 1B 0B 10 5C 63 5D 00 00 00 00 00 00 00 00 05 50 00 01 00 0D 23 63 21 3A 63 63 00 00 00 00 46 03 01 01 00 02 40 00 0B 00 03 63 63 03 18 63 63 5C 00 00 00 00 00 00 02 01 01 4B 00 01 00 07 27 2A 12 2A 5C 63 3A 00 00 00 00 00 00 03 00 01 63 00 01 00 07 63 63 63 0A 63 63 63 00 00 00 00 00 00 00 00 00 48 00 00 00 07 2D 63 63 2C 63 63 63 00 00 00 06 00 00 00 00 02 63 00 00 00 07 63 63 63 63 32 32 32 32 0D 06 00 0F 00 06 45 00 04 01 18 53 6F 6D 6E 69 75 6D 20 20 20 00 +MonoMode8=0 +TGLink8=1 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=21 +EQMidHighFreq8=49 +SendFX1Slot1=YKChorus +SendFX1Slot2=None +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=24 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=42 +SendFX1YKChorusLFORate2=78 +SendFX1YKChorusBypass=0 +SendFX1CloudSeed2Preset=FXDivineInspiration +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=0 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=127 +SendFX1CloudSeed2DryOut=120 +SendFX1CloudSeed2EarlyOut=116 +SendFX1CloudSeed2LateOut=111 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=8 +SendFX1CloudSeed2EarlyDiffuseDelay=93 +SendFX1CloudSeed2EarlyDiffuseModAmount=31 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=12 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=4 +SendFX1CloudSeed2LateLineSize=87 +SendFX1CloudSeed2LateLineModAmount=95 +SendFX1CloudSeed2LateDiffuseDelay=79 +SendFX1CloudSeed2LateDiffuseModAmount=58 +SendFX1CloudSeed2LateLineDecay=74 +SendFX1CloudSeed2LateLineModRate=79 +SendFX1CloudSeed2LateDiffuseFeedback=80 +SendFX1CloudSeed2LateDiffuseModRate=41 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=0 +SendFX1CloudSeed2EqLowpassEnabled=1 +SendFX1CloudSeed2EqLowFreq=9 +SendFX1CloudSeed2EqHighFreq=67 +SendFX1CloudSeed2EqCutoff=65 +SendFX1CloudSeed2EqLowGain=50 +SendFX1CloudSeed2EqHighGain=69 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=18 +SendFX1CloudSeed2SeedDelay=29 +SendFX1CloudSeed2SeedPostDiffusion=36 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=EQ +MasterFXSlot3=None +MasterFXEQLow=2 +MasterFXEQMid=0 +MasterFXEQHigh=5 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=19 +MasterFXEQMidHighFreq=49 +MasterFXEQBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000006_MagicPiano.ini b/performance/004_Mirage/000006_MagicPiano.ini new file mode 100644 index 000000000..63c86bbc6 --- /dev/null +++ b/performance/004_Mirage/000006_MagicPiano.ini @@ -0,0 +1,389 @@ +BankNumber1=0 +VoiceNumber1=18 +MIDIChannel1=1 +Volume1=105 +Pan1=0 +Detune1=-2 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=43 0B 0B 20 63 5A 00 00 02 00 3B 03 01 06 00 00 4E 00 05 00 0C 45 0A 0D 2C 63 5B 00 00 22 07 06 03 00 01 00 03 4C 00 01 00 09 5A 49 33 37 60 3A 00 00 33 0C 0B 03 03 01 00 02 56 01 06 06 06 43 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 61 00 01 00 08 42 0B 00 22 63 4F 00 00 20 00 09 00 00 03 00 02 4A 00 01 01 02 50 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 5E 00 01 00 04 63 63 63 63 32 32 32 32 08 07 00 23 00 00 00 01 00 00 18 6D 44 78 50 69 61 6E 6F 4C 52 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=0 +CompressorEnable1=1 +CompressorPreGain1=2 +CompressorThresh1=-19 +CompressorRatio1=2 +CompressorAttack1=40 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=-2 +EQMid1=0 +EQHigh1=2 +EQGain1=0 +EQLowMidFreq1=22 +EQMidHighFreq1=47 +BankNumber2=0 +VoiceNumber2=18 +MIDIChannel2=1 +Volume2=105 +Pan2=127 +Detune2=1 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=43 0B 0B 20 63 5A 00 00 02 00 3B 03 01 06 00 00 4E 00 05 00 0E 45 0A 0D 2C 63 5B 00 00 22 07 06 03 00 01 00 03 4C 00 01 00 0B 5A 49 33 37 60 3A 00 00 33 0C 0B 03 03 01 00 02 56 01 06 06 06 43 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 61 00 01 00 08 42 0B 00 22 63 4F 00 00 20 00 09 00 00 03 00 02 4A 00 01 01 00 50 15 09 2B 63 4F 00 00 1E 00 00 00 00 07 00 05 5E 00 01 00 03 63 63 63 63 32 32 32 32 08 07 00 23 00 00 00 01 00 00 18 6D 44 78 50 69 61 6E 6F 4C 52 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=0 +CompressorEnable2=1 +CompressorPreGain2=2 +CompressorThresh2=-19 +CompressorRatio2=2 +CompressorAttack2=40 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=-2 +EQMid2=0 +EQHigh2=2 +EQGain2=0 +EQLowMidFreq2=22 +EQMidHighFreq2=47 +BankNumber3=0 +VoiceNumber3=19 +MIDIChannel3=1 +Volume3=65 +Pan3=63 +Detune3=-3 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=4F 2C 1F 2D 63 47 00 00 15 06 00 00 01 04 00 02 51 00 05 00 06 5F 45 0A 2F 63 61 00 00 09 00 3C 00 01 05 00 04 4C 00 01 00 06 5F 0E 0D 30 63 5B 00 00 0F 24 1E 01 01 07 00 06 63 00 01 00 07 5F 2D 1E 2F 63 5E 00 00 05 00 45 00 01 02 03 06 4B 00 07 00 09 58 5C 47 3F 63 43 5B 5A 27 00 63 00 01 02 00 01 52 00 01 00 09 58 1C 15 31 63 5A 00 00 31 20 3F 01 01 04 00 05 63 00 01 00 07 00 00 00 00 32 32 32 32 02 04 00 02 47 08 30 00 00 01 18 52 6F 63 6B 20 41 50 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=0 +CompressorEnable3=1 +CompressorPreGain3=2 +CompressorThresh3=-19 +CompressorRatio3=2 +CompressorAttack3=40 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=-2 +EQMid3=-6 +EQHigh3=2 +EQGain3=0 +EQLowMidFreq3=26 +EQMidHighFreq3=41 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=102 +Pan4=0 +Detune4=1 +Cutoff4=90 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 09 2C 63 63 5D 00 28 0A 0F 03 00 03 00 01 47 00 05 00 07 54 63 11 25 63 63 5C 00 00 00 0E 00 01 03 00 00 47 00 03 00 07 4F 26 0F 1D 63 60 5A 00 2B 02 0F 03 00 04 00 02 4C 00 01 00 0E 4A 2A 15 2F 63 61 00 00 28 07 0A 03 00 05 00 03 5B 00 01 00 07 63 63 19 27 63 63 57 00 00 00 1B 00 01 01 00 01 51 00 01 01 01 42 42 10 2D 63 60 06 00 00 00 00 00 00 04 00 03 5B 00 01 00 09 63 63 63 63 32 32 32 32 01 06 00 23 00 00 00 01 00 01 18 44 72 61 68 74 69 67 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=0 +CompressorEnable4=1 +CompressorPreGain4=2 +CompressorThresh4=-19 +CompressorRatio4=2 +CompressorAttack4=40 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=-2 +EQMid4=0 +EQHigh4=2 +EQGain4=0 +EQLowMidFreq4=22 +EQMidHighFreq4=47 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=1 +Volume5=102 +Pan5=127 +Detune5=-2 +Cutoff5=90 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 09 2C 63 63 5D 00 28 0A 0F 03 00 03 00 01 47 00 05 00 07 54 63 11 25 63 63 5C 00 00 00 0E 00 01 03 00 00 47 00 03 00 07 4F 26 0F 1D 63 60 5A 00 2B 02 0F 03 00 04 00 02 4C 00 01 00 0E 4A 2A 15 2F 63 61 00 00 28 07 0A 03 00 05 00 03 5B 00 01 00 07 63 63 19 27 63 63 57 00 00 00 1B 00 01 01 00 01 51 00 01 01 01 42 42 10 2D 63 60 06 00 00 00 00 00 00 04 00 03 5B 00 01 00 09 63 63 63 63 32 32 32 32 01 06 00 23 00 00 00 01 00 01 18 44 72 61 68 74 69 67 20 20 20 00 +MonoMode5=0 +TGLink5=1 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=1 +CompressorPreGain5=2 +CompressorThresh5=-19 +CompressorRatio5=2 +CompressorAttack5=40 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=-2 +EQMid5=0 +EQHigh5=2 +EQGain5=0 +EQLowMidFreq5=22 +EQMidHighFreq5=47 +BankNumber6=0 +VoiceNumber6=4 +MIDIChannel6=1 +Volume6=14 +Pan6=64 +Detune6=0 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=0 +FX2Send6=99 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=08 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 55 00 10 00 07 0D 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 57 00 0C 00 07 06 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 53 00 08 00 07 0D 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 62 00 10 00 07 12 4A 34 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 0C 00 07 63 4A 36 33 00 63 00 00 27 12 00 00 00 02 00 01 63 00 08 00 07 63 63 63 63 32 32 32 32 1F 00 00 23 00 06 00 01 00 01 18 42 69 6E 67 65 6C 20 20 20 20 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=2 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=-3 +EQMid6=0 +EQHigh6=4 +EQGain6=0 +EQLowMidFreq6=26 +EQMidHighFreq6=51 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=1 +Volume7=18 +Pan7=0 +Detune7=6 +Cutoff7=70 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=54 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode7=0 +TGLink7=2 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=5 +EQMid7=-1 +EQHigh7=4 +EQGain7=0 +EQLowMidFreq7=18 +EQMidHighFreq7=47 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=1 +Volume8=18 +Pan8=125 +Detune8=-6 +Cutoff8=70 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=54 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=4E 63 1A 21 63 63 59 21 32 0B 00 03 03 00 03 00 32 00 03 00 03 63 32 58 48 5D 63 50 00 1B 00 0D 00 00 01 00 00 5B 00 01 32 0E 5D 63 32 45 63 63 51 00 1A 00 0C 03 00 00 03 00 53 00 04 00 07 52 63 30 44 63 63 51 00 2B 0D 0B 03 00 00 03 00 63 00 02 32 06 51 32 63 48 5E 4E 50 00 1A 00 0C 00 00 00 00 00 63 00 01 00 07 54 63 63 4A 63 63 63 00 1A 00 0C 00 00 00 00 00 5E 00 00 00 00 63 63 63 63 31 32 32 32 17 06 00 20 08 04 00 01 04 01 24 4D 31 20 4F 72 67 20 32 33 20 00 +MonoMode8=0 +TGLink8=2 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=5 +EQMid8=-1 +EQHigh8=4 +EQGain8=0 +EQLowMidFreq8=18 +EQMidHighFreq8=47 +SendFX1Slot1=YKChorus +SendFX1Slot2=PlateReverb +SendFX1Slot3=None +SendFX1YKChorusMix=20 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=0 +SendFX1YKChorusLFORate1=27 +SendFX1YKChorusLFORate2=83 +SendFX1YKChorusBypass=0 +SendFX1PlateReverbMix=9 +SendFX1PlateReverbSize=85 +SendFX1PlateReverbHighDamp=23 +SendFX1PlateReverbLowDamp=27 +SendFX1PlateReverbLowPass=78 +SendFX1PlateReverbDiffusion=68 +SendFX1PlateReverbBypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=DreamDelay +SendFX2Slot3=None +SendFX2DreamDelayMix=50 +SendFX2DreamDelayMode=2 +SendFX2DreamDelayTime=19 +SendFX2DreamDelayTimeL=19 +SendFX2DreamDelayTimeR=28 +SendFX2DreamDelayTempo=120 +SendFX2DreamDelayFeedback=60 +SendFX2DreamDelayHighCut=55 +SendFX2DreamDelayBypass=0 +SendFX2ReturnLevel=99 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=EQ +MasterFXSlot3=Compressor +MasterFXEQLow=2 +MasterFXEQMid=0 +MasterFXEQHigh=3 +MasterFXEQGain=0 +MasterFXEQLowMidFreq=22 +MasterFXEQMidHighFreq=48 +MasterFXEQBypass=0 +MasterFXCompressorPreGain=0 +MasterFXCompressorThresh=-3 +MasterFXCompressorRatio=5 +MasterFXCompressorAttack=5 +MasterFXCompressorRelease=85 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000007_Ascension 2TG.ini b/performance/004_Mirage/000007_Ascension 2TG.ini new file mode 100644 index 000000000..4a7a4f918 --- /dev/null +++ b/performance/004_Mirage/000007_Ascension 2TG.ini @@ -0,0 +1,422 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=64 +Pan1=0 +Detune1=-8 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 41 73 63 65 6E 73 69 6F 6E 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=0 +EQMid1=0 +EQHigh1=4 +EQGain1=1 +EQLowMidFreq1=24 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=64 +Pan2=127 +Detune2=8 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 41 73 63 65 6E 73 69 6F 6E 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=0 +CompressorThresh2=-20 +CompressorRatio2=5 +CompressorAttack2=5 +CompressorRelease2=200 +CompressorMakeupGain2=0 +EQLow2=0 +EQMid2=0 +EQHigh2=4 +EQGain2=1 +EQLowMidFreq2=24 +EQMidHighFreq2=44 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=0 +Volume3=56 +Pan3=0 +Detune3=-6 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode3=0 +TGLink3=0 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=0 +EQGain3=0 +EQLowMidFreq3=24 +EQMidHighFreq3=44 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=0 +Volume4=56 +Pan4=127 +Detune4=10 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode4=0 +TGLink4=0 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=0 +EQGain4=0 +EQLowMidFreq4=24 +EQMidHighFreq4=44 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=56 +Pan5=0 +Detune5=0 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=56 +Pan6=127 +Detune6=4 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=56 +Pan7=0 +Detune7=2 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 01 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 08 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 07 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0F 07 3B 0A 1B 09 5A 63 5E 00 00 00 18 00 01 00 00 00 5A 00 00 63 0A 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 0A 07 63 63 63 63 32 32 32 32 00 00 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=56 +Pan8=127 +Detune8=-13 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 00 63 63 63 00 35 00 06 00 00 00 00 00 40 00 06 0A 0D 3C 0C 12 00 59 63 5E 00 00 00 10 00 01 00 01 00 4B 00 03 00 04 39 63 63 21 63 63 63 00 00 00 08 00 01 00 00 00 4A 00 00 00 05 3A 17 03 25 5B 63 60 00 00 00 00 00 00 00 00 02 5D 01 00 0D 07 3B 0A 1B 09 5A 63 5E 00 00 00 17 00 01 00 00 00 5C 00 00 63 07 2F 63 63 2C 63 63 63 00 00 00 00 00 00 00 00 02 63 01 00 00 07 63 1E 63 14 37 32 32 32 00 07 00 02 00 00 63 00 00 03 18 49 4E 49 54 20 56 4F 49 43 45 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=DreamDelay +SendFX1Slot3=CloudSeed2 +SendFX1YKChorusMix=50 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=32 +SendFX1YKChorusLFORate2=82 +SendFX1YKChorusBypass=0 +SendFX1DreamDelayMix=26 +SendFX1DreamDelayMode=1 +SendFX1DreamDelayTime=105 +SendFX1DreamDelayTimeL=105 +SendFX1DreamDelayTimeR=107 +SendFX1DreamDelayTempo=90 +SendFX1DreamDelayFeedback=16 +SendFX1DreamDelayHighCut=52 +SendFX1DreamDelayBypass=0 +SendFX1CloudSeed2Preset=LScreamIntoTheVoid +SendFX1CloudSeed2Interpolation=0 +SendFX1CloudSeed2LowCutEnabled=1 +SendFX1CloudSeed2HighCutEnabled=0 +SendFX1CloudSeed2InputMix=29 +SendFX1CloudSeed2LowCut=37 +SendFX1CloudSeed2HighCut=61 +SendFX1CloudSeed2DryOut=117 +SendFX1CloudSeed2EarlyOut=0 +SendFX1CloudSeed2LateOut=111 +SendFX1CloudSeed2TapEnabled=0 +SendFX1CloudSeed2TapCount=24 +SendFX1CloudSeed2TapDecay=127 +SendFX1CloudSeed2TapPredelay=20 +SendFX1CloudSeed2TapLength=125 +SendFX1CloudSeed2EarlyDiffuseEnabled=1 +SendFX1CloudSeed2EarlyDiffuseCount=8 +SendFX1CloudSeed2EarlyDiffuseDelay=93 +SendFX1CloudSeed2EarlyDiffuseModAmount=31 +SendFX1CloudSeed2EarlyDiffuseFeedback=97 +SendFX1CloudSeed2EarlyDiffuseModRate=31 +SendFX1CloudSeed2LateMode=1 +SendFX1CloudSeed2LateLineCount=10 +SendFX1CloudSeed2LateDiffuseEnabled=1 +SendFX1CloudSeed2LateDiffuseCount=3 +SendFX1CloudSeed2LateLineSize=50 +SendFX1CloudSeed2LateLineModAmount=18 +SendFX1CloudSeed2LateDiffuseDelay=44 +SendFX1CloudSeed2LateDiffuseModAmount=46 +SendFX1CloudSeed2LateLineDecay=66 +SendFX1CloudSeed2LateLineModRate=24 +SendFX1CloudSeed2LateDiffuseFeedback=90 +SendFX1CloudSeed2LateDiffuseModRate=21 +SendFX1CloudSeed2EqLowShelfEnabled=0 +SendFX1CloudSeed2EqHighShelfEnabled=1 +SendFX1CloudSeed2EqLowpassEnabled=0 +SendFX1CloudSeed2EqLowFreq=49 +SendFX1CloudSeed2EqHighFreq=100 +SendFX1CloudSeed2EqCutoff=63 +SendFX1CloudSeed2EqLowGain=70 +SendFX1CloudSeed2EqHighGain=88 +SendFX1CloudSeed2EqCrossSeed=14 +SendFX1CloudSeed2SeedTap=42 +SendFX1CloudSeed2SeedDiffusion=9 +SendFX1CloudSeed2SeedDelay=24 +SendFX1CloudSeed2SeedPostDiffusion=38 +SendFX1CloudSeed2Bypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=Compressor +MasterFXSlot2=None +MasterFXSlot3=None +MasterFXCompressorPreGain=0 +MasterFXCompressorThresh=-7 +MasterFXCompressorRatio=5 +MasterFXCompressorAttack=0 +MasterFXCompressorRelease=200 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=1 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000008_Bananen Mk II.ini b/performance/004_Mirage/000008_Bananen Mk II.ini new file mode 100644 index 000000000..9b9ccf42c --- /dev/null +++ b/performance/004_Mirage/000008_Bananen Mk II.ini @@ -0,0 +1,373 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=111 +Pan1=0 +Detune1=-1 +Cutoff1=99 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=127 +NoteShift1=0 +FX1Send1=99 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 01 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode1=0 +TGLink1=1 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=1 +CompressorEnable1=0 +CompressorPreGain1=6 +CompressorThresh1=-16 +CompressorRatio1=2 +CompressorAttack1=35 +CompressorRelease1=165 +CompressorMakeupGain1=0 +EQLow1=-2 +EQMid1=3 +EQHigh1=6 +EQGain1=0 +EQLowMidFreq1=22 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=1 +MIDIChannel2=1 +Volume2=111 +Pan2=127 +Detune2=1 +Cutoff2=99 +Resonance2=0 +NoteLimitLow2=0 +NoteLimitHigh2=127 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 01 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode2=0 +TGLink2=1 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=1 +CompressorEnable2=0 +CompressorPreGain2=6 +CompressorThresh2=-16 +CompressorRatio2=2 +CompressorAttack2=35 +CompressorRelease2=165 +CompressorMakeupGain2=0 +EQLow2=-2 +EQMid2=3 +EQHigh2=6 +EQGain2=0 +EQLowMidFreq2=22 +EQMidHighFreq2=46 +BankNumber3=0 +VoiceNumber3=1 +MIDIChannel3=1 +Volume3=63 +Pan3=0 +Detune3=4 +Cutoff3=99 +Resonance3=0 +NoteLimitLow3=0 +NoteLimitHigh3=127 +NoteShift3=0 +FX1Send3=99 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 00 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode3=0 +TGLink3=1 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=1 +CompressorEnable3=0 +CompressorPreGain3=6 +CompressorThresh3=-16 +CompressorRatio3=2 +CompressorAttack3=35 +CompressorRelease3=165 +CompressorMakeupGain3=0 +EQLow3=-2 +EQMid3=3 +EQHigh3=6 +EQGain3=0 +EQLowMidFreq3=22 +EQMidHighFreq3=46 +BankNumber4=0 +VoiceNumber4=1 +MIDIChannel4=1 +Volume4=63 +Pan4=127 +Detune4=-5 +Cutoff4=99 +Resonance4=0 +NoteLimitLow4=0 +NoteLimitHigh4=127 +NoteShift4=0 +FX1Send4=99 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=52 4E 1A 4A 63 58 3E 59 00 00 0F 00 01 03 00 02 4A 00 03 00 07 5B 33 07 2A 63 60 51 00 00 00 1A 00 01 03 00 06 54 00 01 00 07 63 5D 41 49 63 63 00 00 38 00 06 00 03 01 00 02 47 01 02 05 06 63 1E 14 3A 63 5E 00 00 28 05 03 03 00 03 00 06 5F 00 01 00 07 5B 63 2C 32 63 63 00 00 03 00 21 00 01 03 00 02 49 00 11 00 0A 57 41 20 3B 63 5E 00 00 39 0A 00 00 00 03 00 02 42 00 01 00 07 63 63 63 63 32 32 32 32 06 04 00 10 00 00 00 00 00 01 18 52 68 6F 64 65 73 20 20 20 20 00 +MonoMode4=0 +TGLink4=1 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=1 +CompressorEnable4=0 +CompressorPreGain4=6 +CompressorThresh4=-16 +CompressorRatio4=2 +CompressorAttack4=35 +CompressorRelease4=165 +CompressorMakeupGain4=0 +EQLow4=-2 +EQMid4=3 +EQHigh4=6 +EQGain4=0 +EQLowMidFreq4=22 +EQMidHighFreq4=46 +BankNumber5=0 +VoiceNumber5=1 +MIDIChannel5=0 +Volume5=56 +Pan5=0 +Detune5=-2 +Cutoff5=99 +Resonance5=0 +NoteLimitLow5=0 +NoteLimitHigh5=127 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=1 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=0 +EQGain5=0 +EQLowMidFreq5=24 +EQMidHighFreq5=44 +BankNumber6=0 +VoiceNumber6=1 +MIDIChannel6=0 +Volume6=56 +Pan6=127 +Detune6=8 +Cutoff6=99 +Resonance6=0 +NoteLimitLow6=0 +NoteLimitHigh6=127 +NoteShift6=0 +FX1Send6=99 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=15 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=0 +EQLowMidFreq6=24 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=1 +MIDIChannel7=0 +Volume7=56 +Pan7=0 +Detune7=4 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=0 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=0 +EQLowMidFreq7=24 +EQMidHighFreq7=44 +BankNumber8=0 +VoiceNumber8=1 +MIDIChannel8=0 +Volume8=56 +Pan8=127 +Detune8=-3 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=0 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 4D 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 63 00 01 00 07 63 63 63 63 32 32 32 32 01 07 00 23 00 00 00 01 00 01 18 49 4E 49 54 20 6D 69 6E 69 44 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=0 +EQLowMidFreq8=24 +EQMidHighFreq8=44 +SendFX1Slot1=YKChorus +SendFX1Slot2=PlateReverb +SendFX1Slot3=None +SendFX1YKChorusMix=4 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=38 +SendFX1YKChorusLFORate2=58 +SendFX1YKChorusBypass=0 +SendFX1PlateReverbMix=9 +SendFX1PlateReverbSize=56 +SendFX1PlateReverbHighDamp=42 +SendFX1PlateReverbLowDamp=13 +SendFX1PlateReverbLowPass=76 +SendFX1PlateReverbDiffusion=65 +SendFX1PlateReverbBypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=Compressor +MasterFXCompressorPreGain=3 +MasterFXCompressorThresh=-16 +MasterFXCompressorRatio=3 +MasterFXCompressorAttack=30 +MasterFXCompressorRelease=145 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=0 +FXBypass=0 diff --git a/performance/004_Mirage/000009_78er DDxFX.ini b/performance/004_Mirage/000009_78er DDxFX.ini new file mode 100644 index 000000000..2e4986eb9 --- /dev/null +++ b/performance/004_Mirage/000009_78er DDxFX.ini @@ -0,0 +1,373 @@ +BankNumber1=0 +VoiceNumber1=1 +MIDIChannel1=1 +Volume1=127 +Pan1=64 +Detune1=0 +Cutoff1=65 +Resonance1=0 +NoteLimitLow1=0 +NoteLimitHigh1=36 +NoteShift1=24 +FX1Send1=30 +FX2Send1=0 +PitchBendRange1=2 +PitchBendStep1=0 +PortamentoMode1=0 +PortamentoGlissando1=0 +PortamentoTime1=0 +VoiceData1=55 63 54 4F 63 63 00 00 00 00 00 00 00 07 00 01 3B 01 02 07 07 63 31 2F 3D 63 5B 00 00 00 00 00 00 00 07 00 04 63 01 01 4D 07 55 63 54 4F 63 63 00 00 00 00 00 00 00 07 00 01 45 01 02 0B 07 63 31 35 3D 63 5B 00 00 00 00 00 00 00 07 00 04 63 01 01 4D 07 63 63 63 4F 63 63 00 00 00 00 00 00 00 07 00 01 44 01 02 3E 07 63 40 34 3D 63 5D 00 00 00 00 00 00 00 07 00 04 63 01 01 4D 07 63 63 63 63 32 32 32 32 04 00 01 23 00 00 00 00 00 00 18 37 38 2D 4B 69 63 6B 20 20 20 00 +MonoMode1=0 +TGLink1=0 +ModulationWheelRange1=99 +ModulationWheelTarget1=1 +FootControlRange1=99 +FootControlTarget1=0 +BreathControlRange1=99 +BreathControlTarget1=0 +AftertouchRange1=99 +AftertouchTarget1=0 +CompressorEnable1=0 +CompressorPreGain1=0 +CompressorThresh1=-20 +CompressorRatio1=5 +CompressorAttack1=5 +CompressorRelease1=200 +CompressorMakeupGain1=0 +EQLow1=4 +EQMid1=0 +EQHigh1=0 +EQGain1=10 +EQLowMidFreq1=18 +EQMidHighFreq1=46 +BankNumber2=0 +VoiceNumber2=12 +MIDIChannel2=1 +Volume2=60 +Pan2=64 +Detune2=36 +Cutoff2=91 +Resonance2=9 +NoteLimitLow2=37 +NoteLimitHigh2=41 +NoteShift2=0 +FX1Send2=99 +FX2Send2=0 +PitchBendRange2=2 +PitchBendStep2=0 +PortamentoMode2=0 +PortamentoGlissando2=0 +PortamentoTime2=0 +VoiceData2=63 63 00 04 63 63 00 00 00 00 00 00 00 00 00 00 5E 01 03 4C 07 5D 63 18 17 63 63 50 00 00 00 00 00 00 00 00 00 61 01 03 1D 06 63 63 00 0A 63 63 00 00 00 00 00 00 00 00 00 00 57 01 03 27 07 54 3E 3F 3E 63 5B 00 00 00 00 00 00 00 00 00 03 5F 01 02 30 07 4E 5C 57 56 63 5F 00 00 00 00 00 00 00 00 00 00 59 01 02 1B 07 4D 48 40 3E 63 5C 00 00 00 00 00 00 00 00 00 02 63 01 02 1A 07 4B 00 4B 4B 32 32 32 32 01 07 01 00 00 00 00 00 04 07 18 37 38 2D 53 6E 61 72 65 20 20 00 +MonoMode2=0 +TGLink2=0 +ModulationWheelRange2=99 +ModulationWheelTarget2=1 +FootControlRange2=99 +FootControlTarget2=0 +BreathControlRange2=99 +BreathControlTarget2=0 +AftertouchRange2=99 +AftertouchTarget2=0 +CompressorEnable2=0 +CompressorPreGain2=2 +CompressorThresh2=-17 +CompressorRatio2=2 +CompressorAttack2=30 +CompressorRelease2=205 +CompressorMakeupGain2=0 +EQLow2=-3 +EQMid2=1 +EQHigh2=1 +EQGain2=12 +EQLowMidFreq2=27 +EQMidHighFreq2=51 +BankNumber3=0 +VoiceNumber3=13 +MIDIChannel3=1 +Volume3=30 +Pan3=11 +Detune3=-28 +Cutoff3=94 +Resonance3=19 +NoteLimitLow3=42 +NoteLimitHigh3=45 +NoteShift3=0 +FX1Send3=78 +FX2Send3=0 +PitchBendRange3=2 +PitchBendStep3=0 +PortamentoMode3=0 +PortamentoGlissando3=0 +PortamentoTime3=0 +VoiceData3=57 63 42 08 62 63 5E 00 00 00 00 00 00 00 00 00 55 01 03 2A 07 59 63 53 00 63 63 61 00 00 00 00 00 00 00 00 00 3F 01 03 1B 07 63 63 63 02 63 63 61 00 00 00 00 00 00 00 03 00 63 01 03 5D 05 4E 45 48 4B 63 57 00 00 00 00 00 00 00 00 00 04 58 01 03 32 05 63 5C 43 56 63 63 00 00 00 00 00 00 00 00 00 01 59 01 03 58 07 58 4E 57 63 63 63 00 00 00 00 00 00 00 00 00 04 55 01 03 42 07 63 63 63 63 32 32 32 32 00 07 00 63 14 00 10 01 05 03 18 37 38 2D 48 69 48 61 74 20 20 00 +MonoMode3=0 +TGLink3=0 +ModulationWheelRange3=99 +ModulationWheelTarget3=1 +FootControlRange3=99 +FootControlTarget3=0 +BreathControlRange3=99 +BreathControlTarget3=0 +AftertouchRange3=99 +AftertouchTarget3=0 +CompressorEnable3=0 +CompressorPreGain3=0 +CompressorThresh3=-20 +CompressorRatio3=5 +CompressorAttack3=5 +CompressorRelease3=200 +CompressorMakeupGain3=0 +EQLow3=0 +EQMid3=0 +EQHigh3=10 +EQGain3=5 +EQLowMidFreq3=44 +EQMidHighFreq3=51 +BankNumber4=0 +VoiceNumber4=23 +MIDIChannel4=1 +Volume4=30 +Pan4=111 +Detune4=43 +Cutoff4=95 +Resonance4=19 +NoteLimitLow4=42 +NoteLimitHigh4=45 +NoteShift4=0 +FX1Send4=78 +FX2Send4=0 +PitchBendRange4=2 +PitchBendStep4=0 +PortamentoMode4=0 +PortamentoGlissando4=0 +PortamentoTime4=0 +VoiceData4=57 63 42 08 62 63 5E 00 00 00 00 00 00 00 00 00 55 01 03 2A 07 59 63 53 00 63 63 61 00 00 00 00 00 00 00 00 00 3F 01 03 1B 07 63 63 63 02 63 63 61 00 00 00 00 00 00 00 03 00 63 01 03 5D 05 4E 45 48 4B 63 57 00 00 00 00 00 00 00 00 00 04 58 01 03 32 05 63 5C 43 56 63 63 00 00 00 00 00 00 00 00 00 01 59 01 03 58 07 58 4E 57 63 63 63 00 00 00 00 00 00 00 00 00 04 55 01 03 42 07 63 63 63 63 32 32 32 32 00 07 00 63 14 00 10 01 05 03 18 37 38 2D 48 69 48 61 74 20 20 00 +MonoMode4=0 +TGLink4=0 +ModulationWheelRange4=99 +ModulationWheelTarget4=1 +FootControlRange4=99 +FootControlTarget4=0 +BreathControlRange4=99 +BreathControlTarget4=0 +AftertouchRange4=99 +AftertouchTarget4=0 +CompressorEnable4=0 +CompressorPreGain4=0 +CompressorThresh4=-20 +CompressorRatio4=5 +CompressorAttack4=5 +CompressorRelease4=200 +CompressorMakeupGain4=0 +EQLow4=0 +EQMid4=0 +EQHigh4=10 +EQGain4=5 +EQLowMidFreq4=44 +EQMidHighFreq4=51 +BankNumber5=0 +VoiceNumber5=13 +MIDIChannel5=1 +Volume5=45 +Pan5=47 +Detune5=41 +Cutoff5=88 +Resonance5=68 +NoteLimitLow5=46 +NoteLimitHigh5=47 +NoteShift5=0 +FX1Send5=99 +FX2Send5=0 +PitchBendRange5=2 +PitchBendStep5=0 +PortamentoMode5=0 +PortamentoGlissando5=0 +PortamentoTime5=0 +VoiceData5=57 63 0C 34 63 63 63 00 00 00 00 00 00 00 00 00 5E 01 03 2A 07 59 63 18 00 63 63 61 00 00 00 00 00 00 00 00 00 63 01 03 48 07 63 63 0B 00 63 63 00 00 00 00 00 00 00 00 00 00 5A 01 03 42 07 50 46 36 39 63 57 00 00 00 00 00 00 00 00 00 04 5D 01 03 45 07 5A 5B 3D 56 63 63 00 00 00 00 00 00 00 00 00 01 59 01 03 5E 07 4A 4F 4D 59 63 63 00 00 00 00 00 00 00 00 00 04 4E 01 03 42 07 63 63 63 63 32 32 32 32 00 07 00 63 07 00 00 01 05 00 18 37 38 2D 6F 48 69 48 61 74 20 00 +MonoMode5=0 +TGLink5=0 +ModulationWheelRange5=99 +ModulationWheelTarget5=1 +FootControlRange5=99 +FootControlTarget5=0 +BreathControlRange5=99 +BreathControlTarget5=0 +AftertouchRange5=99 +AftertouchTarget5=0 +CompressorEnable5=0 +CompressorPreGain5=0 +CompressorThresh5=-20 +CompressorRatio5=5 +CompressorAttack5=5 +CompressorRelease5=200 +CompressorMakeupGain5=0 +EQLow5=0 +EQMid5=0 +EQHigh5=10 +EQGain5=5 +EQLowMidFreq5=44 +EQMidHighFreq5=51 +BankNumber6=0 +VoiceNumber6=24 +MIDIChannel6=1 +Volume6=95 +Pan6=80 +Detune6=0 +Cutoff6=76 +Resonance6=0 +NoteLimitLow6=48 +NoteLimitHigh6=55 +NoteShift6=0 +FX1Send6=14 +FX2Send6=0 +PitchBendRange6=2 +PitchBendStep6=0 +PortamentoMode6=0 +PortamentoGlissando6=0 +PortamentoTime6=0 +VoiceData6=63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 63 63 63 63 63 00 00 00 00 00 00 00 00 00 00 00 01 00 07 63 63 5C 63 63 63 00 00 00 00 00 00 00 00 00 04 3C 01 03 0F 07 63 63 55 63 63 5D 00 00 00 00 00 00 00 00 00 05 63 01 03 0F 07 63 63 63 63 32 32 32 32 00 00 01 23 00 00 00 01 00 00 18 37 38 2D 52 69 6D 20 20 20 20 00 +MonoMode6=0 +TGLink6=0 +ModulationWheelRange6=99 +ModulationWheelTarget6=1 +FootControlRange6=99 +FootControlTarget6=0 +BreathControlRange6=99 +BreathControlTarget6=0 +AftertouchRange6=99 +AftertouchTarget6=0 +CompressorEnable6=0 +CompressorPreGain6=0 +CompressorThresh6=-20 +CompressorRatio6=5 +CompressorAttack6=5 +CompressorRelease6=200 +CompressorMakeupGain6=0 +EQLow6=0 +EQMid6=0 +EQHigh6=0 +EQGain6=16 +EQLowMidFreq6=32 +EQMidHighFreq6=44 +BankNumber7=0 +VoiceNumber7=31 +MIDIChannel7=1 +Volume7=45 +Pan7=0 +Detune7=-2 +Cutoff7=99 +Resonance7=0 +NoteLimitLow7=56 +NoteLimitHigh7=127 +NoteShift7=0 +FX1Send7=99 +FX2Send7=0 +PitchBendRange7=2 +PitchBendStep7=0 +PortamentoMode7=0 +PortamentoGlissando7=0 +PortamentoTime7=0 +VoiceData7=63 63 42 42 63 63 00 00 37 00 0A 00 03 00 00 05 3A 00 01 00 07 63 63 5E 5E 63 63 00 00 00 00 00 00 00 00 00 01 43 00 00 00 07 63 58 31 33 63 5F 00 00 34 00 28 00 00 03 00 03 63 00 00 00 07 63 63 63 63 63 63 00 00 00 00 00 00 00 07 00 00 33 00 05 0C 07 63 63 5B 5C 63 63 00 00 00 00 00 00 00 00 00 00 3B 00 02 27 07 63 63 46 47 63 63 00 00 34 00 28 00 00 03 00 03 5B 00 00 00 07 63 63 63 63 32 32 32 32 09 07 01 23 00 00 00 01 00 00 11 37 38 2D 43 6F 6E 67 61 20 20 00 +MonoMode7=0 +TGLink7=0 +ModulationWheelRange7=99 +ModulationWheelTarget7=1 +FootControlRange7=99 +FootControlTarget7=0 +BreathControlRange7=99 +BreathControlTarget7=0 +AftertouchRange7=99 +AftertouchTarget7=0 +CompressorEnable7=0 +CompressorPreGain7=0 +CompressorThresh7=-20 +CompressorRatio7=5 +CompressorAttack7=5 +CompressorRelease7=200 +CompressorMakeupGain7=0 +EQLow7=0 +EQMid7=0 +EQHigh7=0 +EQGain7=10 +EQLowMidFreq7=44 +EQMidHighFreq7=59 +BankNumber8=0 +VoiceNumber8=31 +MIDIChannel8=1 +Volume8=45 +Pan8=127 +Detune8=2 +Cutoff8=99 +Resonance8=0 +NoteLimitLow8=56 +NoteLimitHigh8=127 +NoteShift8=0 +FX1Send8=99 +FX2Send8=0 +PitchBendRange8=2 +PitchBendStep8=0 +PortamentoMode8=0 +PortamentoGlissando8=0 +PortamentoTime8=0 +VoiceData8=63 63 42 42 63 63 00 00 37 00 0A 00 03 00 00 05 3A 00 01 00 07 63 63 5E 5E 63 63 00 00 00 00 00 00 00 00 00 01 43 00 00 00 07 63 58 31 33 63 5F 00 00 34 28 00 00 00 03 00 03 63 00 00 00 07 63 63 63 63 63 63 00 00 00 00 00 00 00 07 00 00 33 00 05 0C 07 63 63 5B 5C 63 63 00 00 00 00 00 00 00 00 00 00 3B 00 02 27 07 63 63 46 47 63 63 00 00 34 28 00 00 00 03 00 03 5B 00 00 00 07 63 63 63 63 32 32 32 32 09 07 01 23 00 00 00 01 00 00 11 37 38 2D 43 6F 6E 67 61 20 20 00 +MonoMode8=0 +TGLink8=0 +ModulationWheelRange8=99 +ModulationWheelTarget8=1 +FootControlRange8=99 +FootControlTarget8=0 +BreathControlRange8=99 +BreathControlTarget8=0 +AftertouchRange8=99 +AftertouchTarget8=0 +CompressorEnable8=0 +CompressorPreGain8=0 +CompressorThresh8=-20 +CompressorRatio8=5 +CompressorAttack8=5 +CompressorRelease8=200 +CompressorMakeupGain8=0 +EQLow8=0 +EQMid8=0 +EQHigh8=0 +EQGain8=10 +EQLowMidFreq8=44 +EQMidHighFreq8=59 +SendFX1Slot1=PlateReverb +SendFX1Slot2=YKChorus +SendFX1Slot3=None +SendFX1PlateReverbMix=23 +SendFX1PlateReverbSize=29 +SendFX1PlateReverbHighDamp=10 +SendFX1PlateReverbLowDamp=4 +SendFX1PlateReverbLowPass=95 +SendFX1PlateReverbDiffusion=86 +SendFX1PlateReverbBypass=0 +SendFX1YKChorusMix=24 +SendFX1YKChorusEnable1=1 +SendFX1YKChorusEnable2=1 +SendFX1YKChorusLFORate1=30 +SendFX1YKChorusLFORate2=40 +SendFX1YKChorusBypass=0 +SendFX1ReturnLevel=99 +SendFX1Bypass=0 +SendFX2Slot1=None +SendFX2Slot2=None +SendFX2Slot3=None +SendFX2ReturnLevel=0 +SendFX2Bypass=0 +MasterFXSlot1=None +MasterFXSlot2=None +MasterFXSlot3=Compressor +MasterFXCompressorPreGain=2 +MasterFXCompressorThresh=-6 +MasterFXCompressorRatio=2 +MasterFXCompressorAttack=5 +MasterFXCompressorRelease=265 +MasterFXCompressorMakeupGain=0 +MasterFXCompressorHPFilterEnable=0 +MasterFXCompressorBypass=0 +MasterFXBypass=0 +MixerDryLevel=99 +FXBypass=0 diff --git a/performance/DreamDexed Bank 004_Mirage.pdf b/performance/DreamDexed Bank 004_Mirage.pdf new file mode 100644 index 000000000..da6cc517e Binary files /dev/null and b/performance/DreamDexed Bank 004_Mirage.pdf differ diff --git a/src/Makefile b/src/Makefile index 2aed327d1..8ae5fda65 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,18 +9,20 @@ CMSIS_DIR = ../CMSIS_5/CMSIS OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \ mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \ sysexfileloader.o performanceconfig.o perftimer.o \ - effect_platervbstereo.o uibuttons.o midipin.o \ - arm_float_to_q23.o arm_scale_zip_f32.o \ - net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o + effect.o effect_cloudseed2.o effect_platervbstereo.o effect_dreamdelay.o uibuttons.o midipin.o \ + ../CloudSeedCore/DSP/Biquad.o ../CloudSeedCore/DSP/RandomBuffer.o ../CloudSeedCore/DSP/FastSin.o \ + arm_float_to_q23.o arm_zip_f32.o arm_scale_zip_f32.o \ + net/ftpdaemon.o net/ftpworker.o net/applemidi.o net/udpmidi.o net/mdnspublisher.o udpmididevice.o \ + dawcontroller.o + +EXTRACLEAN = $(OBJS) $(OBJS:.o=.d) OPTIMIZE = -O3 +DATE := $(shell git log -1 --format=%cd --date=format:%y%m%d) +COMMIT := $(shell git rev-parse --short HEAD) +VERSION := $(DATE)-$(COMMIT) +DEFINE += -DVERSION=\"$(VERSION)\" + include ./Synth_Dexed.mk include ./Rules.mk - -# Clean target -.PHONY: clean - -clean: - @echo "Cleaning up..." - rm -f $(OBJS) *.o *.d *~ core diff --git a/src/Synth_Dexed.mk b/src/Synth_Dexed.mk index 4d42e6707..2b83a0427 100644 --- a/src/Synth_Dexed.mk +++ b/src/Synth_Dexed.mk @@ -38,12 +38,8 @@ INCLUDE += -I $(CMSIS_DSP_INCLUDE_DIR) INCLUDE += -I $(CMSIS_DSP_PRIVATE_INCLUDE_DIR) INCLUDE += -I $(CMSIS_DSP_COMPUTELIB_INCLUDE_DIR) -DEFINE += -DUSE_FX - ifeq ($(RPI), $(filter $(RPI), 3 4 5)) DEFINE += -DARM_MATH_NEON DEFINE += -DARM_MATH_NEON_EXPERIMENTAL DEFINE += -DHAVE_NEON endif - -EXTRACLEAN = $(SYNTH_DEXED_DIR)/*.[od] $(CMSIS_DSP_SOURCE_DIR)/SupportFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/SupportFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/BasicMathFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/FastMathFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/FilteringFunctions/*.[od] $(CMSIS_DSP_SOURCE_DIR)/CommonTables/*.[od] $(CMSIS_DSP_COMPUTELIB_SRC_DIR)/*.[od] diff --git a/src/arm_scale_zip_f32.c b/src/arm_scale_zip_f32.c index 28ff1c700..a3ac8ac7f 100644 --- a/src/arm_scale_zip_f32.c +++ b/src/arm_scale_zip_f32.c @@ -28,21 +28,21 @@ void arm_scale_zip_f32( { uint32_t blkCnt; /* Loop counter */ - f32x2x2_t res; + f32x4x2_t res; - /* Compute 2 outputs at a time */ - blkCnt = blockSize >> 1U; + /* Compute 4 outputs at a time */ + blkCnt = blockSize >> 2U; while (blkCnt > 0U) { - res.val[0] = vmul_n_f32(vld1_f32(pSrc1), scale); - res.val[1] = vmul_n_f32(vld1_f32(pSrc2), scale); - vst2_f32(pDst, res); + res.val[0] = vmulq_n_f32(vld1q_f32(pSrc1), scale); + res.val[1] = vmulq_n_f32(vld1q_f32(pSrc2), scale); + vst2q_f32(pDst, res); /* Increment pointers */ - pSrc1 += 2; - pSrc2 += 2; - pDst += 4; + pSrc1 += 4; + pSrc2 += 4; + pDst += 8; /* Decrement the loop counter */ blkCnt--; @@ -50,7 +50,7 @@ void arm_scale_zip_f32( /* If the blockSize is not a multiple of 4, compute any remaining output samples here. ** No loop unrolling is used. */ - blkCnt = blockSize & 1; + blkCnt = blockSize & 3; while (blkCnt > 0U) { diff --git a/src/arm_zip_f32.c b/src/arm_zip_f32.c new file mode 100644 index 000000000..012ab3d98 --- /dev/null +++ b/src/arm_zip_f32.c @@ -0,0 +1,82 @@ +#include "arm_zip_f32.h" + +/** + zip two vectors. For floating-point data, the algorithm used is: + +
+      pDst[n] = pSrc1[n], pDst[n+1] = pSrc2[n]   0 <= n < blockSize.
+  
+ + */ + +/** +* @brief Scale two floating-point vector with a scalar and zip after. +* @param[in] pSrc1 points to the input vector 1 +* @param[in] pSrc2 points to the input vector 2 +* @param[out] pDst points to the output vector +* @param[in] blockSize number of samples in the vector +*/ + +#if defined(ARM_MATH_NEON_EXPERIMENTAL) +void arm_zip_f32( + const float32_t * pSrc1, + const float32_t * pSrc2, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + + f32x4x2_t res; + + /* Compute 4 outputs at a time */ + blkCnt = blockSize >> 2U; + + while (blkCnt > 0U) + { + res.val[0] = vld1q_f32(pSrc1); + res.val[1] = vld1q_f32(pSrc2); + vst2q_f32(pDst, res); + + /* Increment pointers */ + pSrc1 += 4; + pSrc2 += 4; + pDst += 8; + + /* Decrement the loop counter */ + blkCnt--; + } + + /* If the blockSize is not a multiple of 4, compute any remaining output samples here. + ** No loop unrolling is used. */ + blkCnt = blockSize & 3; + + while (blkCnt > 0U) + { + *pDst++ = *pSrc1++; + *pDst++ = *pSrc2++; + + /* Decrement the loop counter */ + blkCnt--; + } +} +#else +void arm_zip_f32( + const float32_t * pSrc1, + const float32_t * pSrc2, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + + blkCnt = blockSize; + + while (blkCnt > 0U) + { + *pDst++ = *pSrc1++; + *pDst++ = *pSrc2++; + + /* Decrement the loop counter */ + blkCnt--; + } +} +#endif diff --git a/src/arm_zip_f32.h b/src/arm_zip_f32.h new file mode 100644 index 000000000..61a09c995 --- /dev/null +++ b/src/arm_zip_f32.h @@ -0,0 +1,21 @@ +#pragma once + +#include "arm_math_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** +* @brief zip two floating-point vector. +* @param[in] pSrc1 points to the input vector 1 +* @param[in] pSrc2 points to the input vector 2 +* @param[out] pDst points to the output vector +* @param[in] blockSize number of samples in the vector +*/ +void arm_zip_f32(const float32_t * pSrc1, const float32_t * pSrc2, float32_t * pDst, uint32_t blockSize); + +#ifdef __cplusplus +} +#endif diff --git a/src/circle_stdlib_app.h b/src/circle_stdlib_app.h index 8a69c8280..35ddee0fc 100644 --- a/src/circle_stdlib_app.h +++ b/src/circle_stdlib_app.h @@ -225,72 +225,4 @@ class CStdlibAppStdio: public CStdlibAppScreen CConsole mConsole; }; -/** - * Stdlib application that adds network functionality - * to the CStdlibAppStdio features. - */ -class CStdlibAppNetwork: public CStdlibAppStdio -{ -public: - #define CSTDLIBAPP_WLAN_FIRMWARE_PATH CSTDLIBAPP_DEFAULT_PARTITION "/firmware/" - #define CSTDLIBAPP_WLAN_CONFIG_FILE CSTDLIBAPP_DEFAULT_PARTITION "/wpa_supplicant.conf" - - CStdlibAppNetwork (const char *kernel, - const char *pPartitionName = CSTDLIBAPP_DEFAULT_PARTITION, - const u8 *pIPAddress = 0, // use DHCP if pIPAddress == 0 - const u8 *pNetMask = 0, - const u8 *pDefaultGateway = 0, - const u8 *pDNSServer = 0, - TNetDeviceType DeviceType = NetDeviceTypeEthernet) - : CStdlibAppStdio(kernel, pPartitionName), - mDeviceType (DeviceType), - mWLAN (CSTDLIBAPP_WLAN_FIRMWARE_PATH), - mNet(pIPAddress, pNetMask, pDefaultGateway, pDNSServer, DEFAULT_HOSTNAME, DeviceType), - mWPASupplicant (CSTDLIBAPP_WLAN_CONFIG_FILE) - { - } - - virtual bool Initialize (bool const bWaitForActivate = true) - { - if (!CStdlibAppStdio::Initialize ()) - { - return false; - } - - if (mDeviceType == NetDeviceTypeWLAN) - { - if (!mWLAN.Initialize ()) - { - return false; - } - } - - if (!mNet.Initialize (false)) - { - return false; - } - - if (mDeviceType == NetDeviceTypeWLAN) - { - if (!mWPASupplicant.Initialize ()) - { - return false; - } - } - - while (bWaitForActivate && !mNet.IsRunning ()) - { - mScheduler.Yield (); - } - - return true; - } - -protected: - CScheduler mScheduler; - TNetDeviceType mDeviceType; - CBcm4343Device mWLAN; - CNetSubSystem mNet; - CWPASupplicant mWPASupplicant; -}; #endif diff --git a/src/common.h b/src/common.h index 902f74b7f..d982c821d 100644 --- a/src/common.h +++ b/src/common.h @@ -2,6 +2,8 @@ #ifndef _common_h #define _common_h +#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) + inline long maplong(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } @@ -16,6 +18,12 @@ inline float32_t mapfloat(int val, int in_min, int in_max, float32_t out_min, fl return (val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } +inline long mapfloatr(int val, int in_min, int in_max, float32_t out_min, float32_t out_max) +{ + return lround((val - in_min) * (out_max - out_min) / (in_max - in_min) + out_min); +} + + #define constrain(amt, low, high) ({ \ __typeof__(amt) _amt = (amt); \ __typeof__(low) _low = (low); \ diff --git a/src/config.cpp b/src/config.cpp index 1f817f612..8d67d3039 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -144,8 +144,8 @@ void CConfig::Load (void) m_nST7789Rotation = m_Properties.GetNumber ("ST7789Rotation", 0); m_bST7789SmallFont = m_Properties.GetNumber ("ST7789SmallFont", 0) != 0; - m_nLCDColumns = m_Properties.GetNumber ("LCDColumns", 16); - m_nLCDRows = m_Properties.GetNumber ("LCDRows", 2); + m_nLCDColumns = std::max(MinLCDColumns, m_Properties.GetNumber ("LCDColumns", 16)); + m_nLCDRows = std::max(MinLCDRows, m_Properties.GetNumber ("LCDRows", 2)); m_nButtonPinPrev = m_Properties.GetNumber ("ButtonPinPrev", 0); m_nButtonPinNext = m_Properties.GetNumber ("ButtonPinNext", 0); @@ -162,6 +162,7 @@ void CConfig::Load (void) m_nDoubleClickTimeout = m_Properties.GetNumber ("DoubleClickTimeout", 400); m_nLongPressTimeout = m_Properties.GetNumber ("LongPressTimeout", 600); + m_nMIDIRelativeDebounceTime = m_Properties.GetNumber ("MIDIRelativeDebounceTime", 0); m_nButtonPinPgmUp = m_Properties.GetNumber ("ButtonPinPgmUp", 0); m_nButtonPinPgmDown = m_Properties.GetNumber ("ButtonPinPgmDown", 0); @@ -179,25 +180,43 @@ void CConfig::Load (void) m_nMIDIButtonCh = m_Properties.GetNumber ("MIDIButtonCh", 0); m_nMIDIButtonNotes = m_Properties.GetNumber ("MIDIButtonNotes", 0); + m_nMIDIButtonPrev = m_Properties.GetNumber ("MIDIButtonPrev", 0); m_nMIDIButtonNext = m_Properties.GetNumber ("MIDIButtonNext", 0); m_nMIDIButtonBack = m_Properties.GetNumber ("MIDIButtonBack", 0); m_nMIDIButtonSelect = m_Properties.GetNumber ("MIDIButtonSelect", 0); m_nMIDIButtonHome = m_Properties.GetNumber ("MIDIButtonHome", 0); + m_MIDIButtonActionPrev = m_Properties.GetString ("MIDIButtonActionPrev", ""); + m_MIDIButtonActionNext = m_Properties.GetString ("MIDIButtonActionNext", ""); + m_MIDIButtonActionBack = m_Properties.GetString ("MIDIButtonActionBack", ""); + m_MIDIButtonActionSelect = m_Properties.GetString ("MIDIButtonActionSelect", ""); + m_MIDIButtonActionHome = m_Properties.GetString ("MIDIButtonActionHome", ""); + m_nMIDIButtonPgmUp = m_Properties.GetNumber ("MIDIButtonPgmUp", 0); m_nMIDIButtonPgmDown = m_Properties.GetNumber ("MIDIButtonPgmDown", 0); m_nMIDIButtonBankUp = m_Properties.GetNumber ("MIDIButtonBankUp", 0); m_nMIDIButtonBankDown = m_Properties.GetNumber ("MIDIButtonBankDown", 0); m_nMIDIButtonTGUp = m_Properties.GetNumber ("MIDIButtonTGUp", 0); m_nMIDIButtonTGDown = m_Properties.GetNumber ("MIDIButtonTGDown", 0); - + + m_MIDIButtonActionPgmUp = m_Properties.GetString ("MIDIButtonActionPgmUp", ""); + m_MIDIButtonActionPgmDown = m_Properties.GetString ("MIDIButtonActionPgmDown", ""); + m_MIDIButtonActionBankUp = m_Properties.GetString ("MIDIButtonActionBankUp", ""); + m_MIDIButtonActionBankDown = m_Properties.GetString ("MIDIButtonActionBankDown", ""); + m_MIDIButtonActionTGUp = m_Properties.GetString ("MIDIButtonActionTGUp", ""); + m_MIDIButtonActionTGDown = m_Properties.GetString ("MIDIButtonActionTGDown", ""); + + m_bDAWControllerEnabled = m_Properties.GetNumber ("DAWControllerEnabled", 0) != 0; + m_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0; m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9); m_bMIDIDumpEnabled = m_Properties.GetNumber ("MIDIDumpEnabled", 0) != 0; m_bProfileEnabled = m_Properties.GetNumber ("ProfileEnabled", 0) != 0; + m_bLogThrottling = m_Properties.GetNumber("LogThrottling", 0); + m_bPerformanceSelectToLoad = m_Properties.GetNumber ("PerformanceSelectToLoad", 0) != 0; m_bPerformanceSelectChannel = m_Properties.GetNumber ("PerformanceSelectChannel", 0); @@ -206,20 +225,17 @@ void CConfig::Load (void) m_bNetworkDHCP = m_Properties.GetNumber ("NetworkDHCP", 0) != 0; m_NetworkType = m_Properties.GetString ("NetworkType", "wlan"); m_NetworkHostname = m_Properties.GetString ("NetworkHostname", "MiniDexed"); - m_INetworkIPAddress = m_Properties.GetIPAddress("NetworkIPAddress") != 0; - m_INetworkSubnetMask = m_Properties.GetIPAddress("NetworkSubnetMask") != 0; - m_INetworkDefaultGateway = m_Properties.GetIPAddress("NetworkDefaultGateway") != 0; + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkIPAddress")) m_INetworkIPAddress.Set (pIP); + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkSubnetMask")) m_INetworkSubnetMask.Set (pIP); + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkDefaultGateway")) m_INetworkDefaultGateway.Set (pIP); m_bSyslogEnabled = m_Properties.GetNumber ("NetworkSyslogEnabled", 0) != 0; - m_INetworkDNSServer = m_Properties.GetIPAddress("NetworkDNSServer") != 0; + if (const u8 *pIP = m_Properties.GetIPAddress("NetworkDNSServer")) m_INetworkDNSServer.Set (pIP); m_bNetworkFTPEnabled = m_Properties.GetNumber("NetworkFTPEnabled", 0) != 0; - - const u8 *pSyslogServerIP = m_Properties.GetIPAddress ("NetworkSyslogServerIPAddress"); - if (pSyslogServerIP) - { - m_INetworkSyslogServerIPAddress.Set (pSyslogServerIP); - } + if (const u8 *pIP = m_Properties.GetIPAddress ("NetworkSyslogServerIPAddress")) m_INetworkSyslogServerIPAddress.Set (pIP); m_nMasterVolume = m_Properties.GetNumber ("MasterVolume", 64); + + m_nDefaultScreen = m_Properties.GetNumber ("DefaultScreen", 0); } unsigned CConfig::GetToneGenerators (void) const @@ -583,6 +599,11 @@ unsigned CConfig::GetLongPressTimeout (void) const return m_nLongPressTimeout; } +unsigned CConfig::GetMIDIRelativeDebounceTime(void) const +{ + return m_nMIDIRelativeDebounceTime; +} + unsigned CConfig::GetButtonPinPgmUp (void) const { return m_nButtonPinPgmUp; @@ -678,6 +699,31 @@ unsigned CConfig::GetMIDIButtonHome (void) const return m_nMIDIButtonHome; } +const char *CConfig::GetMIDIButtonActionPrev (void) const +{ + return m_MIDIButtonActionPrev.c_str(); +} + +const char *CConfig::GetMIDIButtonActionNext (void) const +{ + return m_MIDIButtonActionNext.c_str(); +} + +const char *CConfig::GetMIDIButtonActionBack (void) const +{ + return m_MIDIButtonActionBack.c_str(); +} + +const char *CConfig::GetMIDIButtonActionSelect (void) const +{ + return m_MIDIButtonActionSelect.c_str(); +} + +const char *CConfig::GetMIDIButtonActionHome (void) const +{ + return m_MIDIButtonActionHome.c_str(); +} + unsigned CConfig::GetMIDIButtonPgmUp (void) const { return m_nMIDIButtonPgmUp; @@ -708,6 +754,41 @@ unsigned CConfig::GetMIDIButtonTGDown (void) const return m_nMIDIButtonTGDown; } +const char *CConfig::GetMIDIButtonActionPgmUp (void) const +{ + return m_MIDIButtonActionPgmUp.c_str(); +} + +const char *CConfig::GetMIDIButtonActionPgmDown (void) const +{ + return m_MIDIButtonActionPgmDown.c_str(); +} + +const char *CConfig::GetMIDIButtonActionBankUp (void) const +{ + return m_MIDIButtonActionBankUp.c_str(); +} + +const char *CConfig::GetMIDIButtonActionBankDown (void) const +{ + return m_MIDIButtonActionBankDown.c_str(); +} + +const char *CConfig::GetMIDIButtonActionTGUp (void) const +{ + return m_MIDIButtonActionTGUp.c_str(); +} + +const char *CConfig::GetMIDIButtonActionTGDown (void) const +{ + return m_MIDIButtonActionTGDown.c_str(); +} + +bool CConfig::GetDAWControllerEnabled (void) const +{ + return m_bDAWControllerEnabled; +} + bool CConfig::GetEncoderEnabled (void) const { return m_bEncoderEnabled; @@ -733,6 +814,11 @@ bool CConfig::GetProfileEnabled (void) const return m_bProfileEnabled; } +bool CConfig::GetLogThrottling (void) const +{ + return m_bLogThrottling; +} + bool CConfig::GetPerformanceSelectToLoad (void) const { return m_bPerformanceSelectToLoad; @@ -764,22 +850,22 @@ const char *CConfig::GetNetworkHostname (void) const return m_NetworkHostname.c_str(); } -CIPAddress CConfig::GetNetworkIPAddress (void) const +const CIPAddress& CConfig::GetNetworkIPAddress (void) const { return m_INetworkIPAddress; } -CIPAddress CConfig::GetNetworkSubnetMask (void) const +const CIPAddress& CConfig::GetNetworkSubnetMask (void) const { return m_INetworkSubnetMask; } -CIPAddress CConfig::GetNetworkDefaultGateway (void) const +const CIPAddress& CConfig::GetNetworkDefaultGateway (void) const { return m_INetworkDefaultGateway; } -CIPAddress CConfig::GetNetworkDNSServer (void) const +const CIPAddress& CConfig::GetNetworkDNSServer (void) const { return m_INetworkDNSServer; } @@ -789,7 +875,7 @@ bool CConfig::GetSyslogEnabled (void) const return m_bSyslogEnabled; } -CIPAddress CConfig::GetNetworkSyslogServerIPAddress (void) const +const CIPAddress& CConfig::GetNetworkSyslogServerIPAddress (void) const { return m_INetworkSyslogServerIPAddress; } diff --git a/src/config.h b/src/config.h index aaf247623..c2dc7c776 100644 --- a/src/config.h +++ b/src/config.h @@ -43,6 +43,9 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = 1; static const unsigned AllToneGenerators = 1; static const unsigned DefToneGenerators = AllToneGenerators; + static const unsigned FXMixers = 0; + static const unsigned FXChains = 0; + static const unsigned MasterFX = FXMixers; #else #if (RASPPI==4 || RASPPI==5) // Pi 4 and 5 quad core @@ -54,6 +57,9 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; static const unsigned AllToneGenerators = TGsCore1 + TGsCore1Opt + 2*TGsCore23 + 2*TGsCore23Opt; static const unsigned DefToneGenerators = MinToneGenerators; + static const unsigned FXMixers = 2; + static const unsigned FXChains = FXMixers + 1; + static const unsigned MasterFX = FXMixers; #else // Pi 2 or 3 quad core static const unsigned TGsCore1 = 2; // process 2 TGs on core 1 @@ -63,6 +69,9 @@ class CConfig // Configuration for MiniDexed static const unsigned MinToneGenerators = TGsCore1 + 2*TGsCore23; static const unsigned AllToneGenerators = MinToneGenerators; static const unsigned DefToneGenerators = AllToneGenerators; + static const unsigned FXMixers = 2; + static const unsigned FXChains = FXMixers + 1; + static const unsigned MasterFX = FXMixers; #endif #endif @@ -89,9 +98,8 @@ class CConfig // Configuration for MiniDexed static const unsigned MaxUSBMIDIDevices = 4; #endif - // TODO - Leave this for uimenu.cpp for now, but it will need to be dynamic at some point... - static const unsigned LCDColumns = 16; // HD44780 LCD - static const unsigned LCDRows = 2; + static const unsigned MinLCDColumns = 16; // HD44780 LCD + static const unsigned MinLCDRows = 2; public: CConfig (FATFS *pFileSystem); @@ -191,6 +199,7 @@ class CConfig // Configuration for MiniDexed // Timeouts for button events in milliseconds unsigned GetDoubleClickTimeout (void) const; unsigned GetLongPressTimeout (void) const; + unsigned GetMIDIRelativeDebounceTime (void) const; // GPIO Button Program and TG Selection // GPIO pin numbers are chip numbers, not header positions @@ -212,12 +221,20 @@ class CConfig // Configuration for MiniDexed // MIDI Button Navigation unsigned GetMIDIButtonCh (void) const; unsigned GetMIDIButtonNotes (void) const; + unsigned GetMIDIButtonPrev (void) const; unsigned GetMIDIButtonNext (void) const; unsigned GetMIDIButtonBack (void) const; unsigned GetMIDIButtonSelect (void) const; unsigned GetMIDIButtonHome (void) const; + // Action type for Midi buttons: "click", "doubleclick", "longpress", "dec", "inc", "" + const char *GetMIDIButtonActionPrev (void) const; + const char *GetMIDIButtonActionNext (void) const; + const char *GetMIDIButtonActionBack (void) const; + const char *GetMIDIButtonActionSelect (void) const; + const char *GetMIDIButtonActionHome (void) const; + // MIDI Button Program and TG Selection unsigned GetMIDIButtonPgmUp (void) const; unsigned GetMIDIButtonPgmDown (void) const; @@ -226,6 +243,16 @@ class CConfig // Configuration for MiniDexed unsigned GetMIDIButtonTGUp (void) const; unsigned GetMIDIButtonTGDown (void) const; + // Action type for buttons: "click", "doubleclick", "longpress", "dec", "inc", "" + const char *GetMIDIButtonActionPgmUp (void) const; + const char *GetMIDIButtonActionPgmDown (void) const; + const char *GetMIDIButtonActionBankUp (void) const; + const char *GetMIDIButtonActionBankDown (void) const; + const char *GetMIDIButtonActionTGUp (void) const; + const char *GetMIDIButtonActionTGDown (void) const; + + bool GetDAWControllerEnabled (void) const; + // KY-040 Rotary Encoder // GPIO pin numbers are chip numbers, not header positions bool GetEncoderEnabled (void) const; @@ -235,24 +262,27 @@ class CConfig // Configuration for MiniDexed // Debug bool GetMIDIDumpEnabled (void) const; bool GetProfileEnabled (void) const; - + bool GetLogThrottling (void) const; + // Load performance mode. 0 for load just rotating encoder, 1 load just when Select is pushed bool GetPerformanceSelectToLoad (void) const; unsigned GetPerformanceSelectChannel (void) const; unsigned GetMasterVolume() const { return m_nMasterVolume; } + unsigned GetDefaultScreen() const { return m_nDefaultScreen; } + // Network bool GetNetworkEnabled (void) const; bool GetNetworkDHCP (void) const; const char *GetNetworkType (void) const; const char *GetNetworkHostname (void) const; - CIPAddress GetNetworkIPAddress (void) const; - CIPAddress GetNetworkSubnetMask (void) const; - CIPAddress GetNetworkDefaultGateway (void) const; - CIPAddress GetNetworkDNSServer (void) const; + const CIPAddress& GetNetworkIPAddress (void) const; + const CIPAddress& GetNetworkSubnetMask (void) const; + const CIPAddress& GetNetworkDefaultGateway (void) const; + const CIPAddress& GetNetworkDNSServer (void) const; bool GetSyslogEnabled (void) const; - CIPAddress GetNetworkSyslogServerIPAddress (void) const; + const CIPAddress& GetNetworkSyslogServerIPAddress (void) const; bool GetNetworkFTPEnabled (void) const; private: @@ -344,8 +374,21 @@ class CConfig // Configuration for MiniDexed std::string m_ButtonActionTGUp; std::string m_ButtonActionTGDown; + std::string m_MIDIButtonActionPrev; + std::string m_MIDIButtonActionNext; + std::string m_MIDIButtonActionBack; + std::string m_MIDIButtonActionSelect; + std::string m_MIDIButtonActionHome; + std::string m_MIDIButtonActionPgmUp; + std::string m_MIDIButtonActionPgmDown; + std::string m_MIDIButtonActionBankUp; + std::string m_MIDIButtonActionBankDown; + std::string m_MIDIButtonActionTGUp; + std::string m_MIDIButtonActionTGDown; + unsigned m_nDoubleClickTimeout; unsigned m_nLongPressTimeout; + unsigned m_nMIDIRelativeDebounceTime; unsigned m_nMIDIButtonCh; unsigned m_nMIDIButtonNotes; @@ -361,6 +404,8 @@ class CConfig // Configuration for MiniDexed unsigned m_nMIDIButtonTGUp; unsigned m_nMIDIButtonTGDown; + bool m_bDAWControllerEnabled; + bool m_bEncoderEnabled; unsigned m_nEncoderPinClock; unsigned m_nEncoderPinData; @@ -371,6 +416,8 @@ class CConfig // Configuration for MiniDexed unsigned m_bPerformanceSelectChannel; unsigned m_nMasterVolume; // Master volume 0-127 + + unsigned m_nDefaultScreen; // 0 Default, 1 Performance // Network bool m_bNetworkEnabled; @@ -384,6 +431,8 @@ class CConfig // Configuration for MiniDexed bool m_bSyslogEnabled; CIPAddress m_INetworkSyslogServerIPAddress; bool m_bNetworkFTPEnabled; + + bool m_bLogThrottling; }; #endif diff --git a/src/dawcontroller.cpp b/src/dawcontroller.cpp new file mode 100644 index 000000000..a90cbacfa --- /dev/null +++ b/src/dawcontroller.cpp @@ -0,0 +1,2436 @@ +// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi +// Copyright (C) 2024 The MiniDexed Team +// +// This program 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 + +#include "dawcontroller.h" +#include "midikeyboard.h" +#include "minidexed.h" +#include "midi.h" + +#define LINELEN 18 + +#define MIDI_DAW_CHANGE 0b10000 +#define MIDI_DAW_VOICE 1 +#define MIDI_DAW_TOGGLE_MONO 3 +#define MIDI_DAW_TOGGLE_PORTA_GLISS 4 +#define MIDI_DAW_TOGGLE_TG 5 +#define MIDI_DAW_SELECT_TG 6 +#define MIDI_DAW_SELECT_CHAN_TG 7 +#define MIDI_DAW_MENU_SELECT 8 +#define MIDI_DAW_MENU_BACK 9 +#define MIDI_DAW_MENU_PREV 10 +#define MIDI_DAW_MENU_NEXT 11 +#define MIDI_DAW_MENU_PRESS_PREV 12 +#define MIDI_DAW_MENU_PRESS_NEXT 13 +#define MIDI_DAW_MENU_HOME 14 +#define MIDI_DAW_DISPLAY_MODE_TOGGLE 17 +#define MIDI_DAW_ENC_VALUES_TOGGLE 18 +#define MIDI_DAW_ENC_0 20 +#define MIDI_DAW_ENC_1 21 +#define MIDI_DAW_ENC_2 22 +#define MIDI_DAW_ENC_3 23 +#define MIDI_DAW_ENC_4 24 +#define MIDI_DAW_ENC_5 25 +#define MIDI_DAW_ENC_6 26 +#define MIDI_DAW_ENC_7 27 +#define MIDI_DAW_ENC_8 28 +#define MIDI_DAW_FADER_0 29 +#define MIDI_DAW_FADER_1 30 +#define MIDI_DAW_FADER_2 31 +#define MIDI_DAW_FADER_3 32 +#define MIDI_DAW_FADER_4 33 +#define MIDI_DAW_FADER_5 34 +#define MIDI_DAW_FADER_6 35 +#define MIDI_DAW_FADER_7 36 +#define MIDI_DAW_MASTER_VOLUME 37 + + +static void ArturiaDisplayWrite (CMIDIKeyboard *pKeyboard, const u8 *pHdr, const unsigned nHdrSize, + size_t nLineMaxLen, const bool bFill1, const bool bFill2, const char *pMenu, + const char *pParam, const char *pValue, + const bool bArrowLeft, const bool bArrowRight, const bool bShowArrows) +{ + size_t nParamLen = std::min (nLineMaxLen, strlen (pParam)); + size_t nMenuLen = strlen (pMenu); + size_t nFill1Len = bFill1 && nLineMaxLen > nParamLen + nMenuLen ? + nLineMaxLen - nParamLen - nMenuLen : 1; + + nFill1Len = std:: min (nLineMaxLen - nParamLen, nFill1Len); + nMenuLen = std::min (nLineMaxLen - nParamLen - nFill1Len, nMenuLen); + + size_t nLine1Len = nParamLen + nFill1Len + nMenuLen; + + size_t nArrowsLen = bShowArrows ? 2 : 0; + size_t nValueLen = std::min (nLineMaxLen - nArrowsLen, strlen (pValue)); + size_t nFill2Len = bFill2 ? nLineMaxLen - nArrowsLen - nValueLen : 0; + size_t nLine2Len = nValueLen + nFill2Len + nArrowsLen; + + size_t nOffset = 0; + + uint8_t pLines[nHdrSize + nLine1Len + 2 + nLine2Len + 2]; + + memcpy (pLines, pHdr, nHdrSize); + nOffset += nHdrSize; + + memcpy (&pLines[nOffset], pParam, nParamLen); + nOffset += nParamLen; + + memset (&pLines[nOffset], ' ', nFill1Len); + nOffset += nFill1Len; + + memcpy (&pLines[nOffset], pMenu, nMenuLen); + nOffset += nMenuLen; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0x02; + + if (bShowArrows) + pLines[nOffset++] = bArrowLeft ? '<' : ' '; + + memcpy (&pLines[nOffset], pValue, nValueLen); + nOffset += nValueLen; + + memset (&pLines[nOffset], ' ', nFill2Len); + nOffset += nFill2Len; + + if (bShowArrows) + pLines[nOffset++] = bArrowRight ? '>' : ' '; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0xF7; + + // block character (0xFF) is not supported over MIDI, change to 0x7f + for (unsigned i = 0; i < sizeof pLines; ++i) + if (pLines[i] == 0xFF) + pLines[i] = 0x7F; + + pKeyboard->SendDisplay (pLines, nOffset, 0); +} + +enum ControlType +{ + CT_KNOB = 3, + CT_FADER, + CT_PAD, +}; + +enum HideAfter +{ + HA_NO = 0, + HA_YES = 2, +}; + +static std::string to_string (int nValue, int nWidth) +{ + return std::to_string(nValue); +} + +static std::string to_percent (int nValue, int nWidth) +{ + return std::to_string(mapfloatr (nValue, 0, 127, 0, 100)) + "%"; +} + +static std::string to_on_off (int nValue, int nWidth) +{ + return nValue < 64 ? "Off" : "On"; +} + +static std::string to_selected (int nValue, int nWidth) +{ + return nValue < 64 ? "Deselected" : "Selected"; +} + +std::string to_midi_channel (int nValue) +{ + switch (nValue) + { + case CMIDIDevice::OmniMode: return "Omni"; + case CMIDIDevice::Disabled: return "Off"; + default: return std::to_string (nValue + 1); + } +} + +static void ArturiaDisplayInfoWrite (CMIDIKeyboard *pKeyboard, const uint8_t pDisplayHdr[3], ControlType Type, u8 uValue, const char *pName, const char *pValue) +{ + const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, pDisplayHdr[0], pDisplayHdr[1], pDisplayHdr[2], 0x1F, Type, HA_NO, uValue, 0x00, 0x00, 0x01}; + + int nLine1Len = strlen (pName); + int nLine2Len = strlen (pValue); + int nOffset = 0; + + uint8_t pLines[sizeof pHdr + nLine1Len + 2 + nLine2Len + 2]; + + memcpy (pLines, pHdr, sizeof pHdr); + nOffset += sizeof pHdr; + + memcpy (pLines + nOffset, pName, nLine1Len); + nOffset += nLine1Len; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0x02; + + memcpy (pLines + nOffset, pValue, nLine2Len); + nOffset += nLine2Len; + + pLines[nOffset++] = 0x00; + pLines[nOffset++] = 0xf7; + + pKeyboard->SendDisplay (pLines, nOffset, 0); +} + +static void ArturiaShowNewCCValue (CMIDIKeyboard *pKeyboard, const uint8_t pDisplayHdr[3], u8 ucCh, u8 ucCC, u8 ucValue) +{ + char line1[LINELEN]; + char line2[LINELEN]; + + switch (ucCC) + { + case MIDI_CC_PORTAMENTO_TIME: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Portamento Time", line2); + break; + case MIDI_CC_VOLUME: + snprintf(line1, LINELEN, "Volume Ch %d", ucCh + 1); + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 100)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_FADER, ucValue, line1, line2); + break; + case MIDI_CC_FREQUENCY_CUTOFF: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Cutoff", line2); + break; + case MIDI_CC_RESONANCE: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Resonance", line2); + break; + case MIDI_CC_EFFECT1_SEND: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Effect1 Send", line2); + break; + case MIDI_CC_EFFECT2_SEND: + snprintf(line2, LINELEN, "%ld%%", mapfloatr (ucValue, 0, 127, 0, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Effect2 Send", line2); + break; + case MIDI_CC_DETUNE_LEVEL: + snprintf(line2, LINELEN, "%ld", mapfloatr (ucValue, 1, 127, -99, 99)); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Detune", line2); + break; + case MIDI_CC_PAN_POSITION: + snprintf(line2, LINELEN, "%d", ucValue); + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_KNOB, ucValue, "Pan", line2); + break; + case MIDI_CC_SUSTAIN: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Sustain", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_PORTAMENTO: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Portamento", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_SOSTENUTO: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Sostenuto", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_HOLD2: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "Hold", ucValue > 64 ? "On" : "Off"); + break; + case MIDI_CC_ALL_SOUND_OFF: + ArturiaDisplayInfoWrite (pKeyboard, pDisplayHdr, CT_PAD, ucValue, "All Sound Off", ""); + break; + } +} + +static void HandleMenuEvents (CUserInterface *pUI, u8 ucDC) +{ + switch (ucDC) + { + case MIDI_DAW_MENU_SELECT: + pUI->MIDIEventHandler (CUIMenu::MenuEventSelect); + break; + case MIDI_DAW_MENU_BACK: + pUI->MIDIEventHandler (CUIMenu::MenuEventBack); + break; + case MIDI_DAW_MENU_PREV: + pUI->MIDIEventHandler (CUIMenu::MenuEventStepDown); + break; + case MIDI_DAW_MENU_NEXT: + pUI->MIDIEventHandler (CUIMenu::MenuEventStepUp); + break; + case MIDI_DAW_MENU_PRESS_PREV: + pUI->MIDIEventHandler (CUIMenu::MenuEventPressAndStepDown); + break; + case MIDI_DAW_MENU_PRESS_NEXT: + pUI->MIDIEventHandler (CUIMenu::MenuEventPressAndStepUp); + break; + case MIDI_DAW_MENU_HOME: + pUI->MIDIEventHandler (CUIMenu::MenuEventHome); + break; + } +} + +class CDAWConnection +{ +public: + virtual void DisplayWrite (const char *pMenu, const char *pParam, + const char *pValue, bool bArrowDown, bool bArrowUp) = 0; + virtual void UpdateState () = 0; + virtual void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) = 0; + virtual void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) = 0; + virtual ~CDAWConnection (void) = default; + + static const unsigned nDefaultDisplayUpdateDelay = 2000; +}; + +struct CColor +{ + uint8_t r; + uint8_t g; + uint8_t b; +}; + +bool operator==(const CColor& l, const CColor& r) +{ + return l.r == r.r && l.g == r.g && l.b == r.b; +} + +bool operator!=(const CColor& l, const CColor& r) +{ + return !(l == r); +} + +static CColor padColors[8] = { + {0x3F, 0x3F, 0x11}, + {0x11, 0x11, 0x3F}, + {0x3F, 0x11, 0x3F}, + {0x11, 0x3F, 0x11}, + {0x3F, 0x11, 0x11}, + {0x11, 0x3F, 0x3F}, + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00}, +}; + +static CColor altPadColors[8] = { + {0x3F, 0x3F, 0x11}, + {0x11, 0x21, 0x3F}, + {0x3F, 0x11, 0x3F}, + {0x11, 0x3F, 0x11}, + {0x3F, 0x11, 0x11}, + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00}, +}; + +static CColor chColors[CMIDIDevice::TChannel::Disabled + 1] = { + {0x7F, 0x00, 0x00}, // 1 + {0x7F, 0x40, 0x00}, // 2 + {0x7F, 0x40, 0x40}, // 3 + {0x7F, 0x40, 0x7F}, // 4 + {0x7F, 0x7F, 0x00}, // 5 + {0x7F, 0x7F, 0x40}, // 6 + {0x7F, 0x7F, 0x7F}, // 7 + {0x40, 0x00, 0x40}, // 8 + {0x40, 0x40, 0x00}, // 9 + {0x40, 0x40, 0x40}, // 10 + {0x40, 0x40, 0x7F}, // 11 + {0x40, 0x7F, 0x00}, // 12 + {0x40, 0x7F, 0x40}, // 13 + {0x40, 0x7F, 0x7F}, // 14 + {0x00, 0x00, 0x40}, // 15 + {0x00, 0x40, 0x00}, // 16 + {0x7F, 0x7F, 0x7F}, // Omni + {0x00, 0x00, 0x00}, // Disabled +}; + +static CColor invalidColor = {0x80, 0x80, 0x80}; + +static CColor chColors_kl2[CMIDIDevice::TChannel::Disabled + 1] = { + {0x1F, 0x00, 0x00}, // 1 + {0x1F, 0x10, 0x00}, // 2 + {0x1F, 0x10, 0x10}, // 3 + {0x1F, 0x10, 0x1F}, // 4 + {0x1F, 0x1F, 0x00}, // 5 + {0x1F, 0x1F, 0x10}, // 6 + {0x1F, 0x1F, 0x1F}, // 7 + {0x10, 0x00, 0x10}, // 8 + {0x10, 0x10, 0x00}, // 9 + {0x10, 0x10, 0x10}, // 10 + {0x10, 0x10, 0x1F}, // 11 + {0x10, 0x1F, 0x00}, // 12 + {0x10, 0x1F, 0x10}, // 13 + {0x10, 0x1F, 0x1F}, // 14 + {0x00, 0x00, 0x10}, // 15 + {0x00, 0x10, 0x00}, // 16 + {0x1F, 0x1F, 0x1F}, // Omni + {0x00, 0x00, 0x00}, // Disabled +}; + +class CMiniLab3DawConnection : public CDAWConnection +{ +public: + CMiniLab3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + enum TPadID { + MonoPad = 0, + PortamentoPad = 1, + SostenutoPad = 2, + SustainPad = 3, + SoundOffPad = 4, + HoldPad = 5, + TBDPad7 = 6, + ATPad = 7, + }; + enum TBankID { + BankA = 0x34, + BankB = 0x44, + }; + + static const u8 AllOP = 8; + + void DisplayWriteSimple (const char *pMenu, const char *pParam, const char *pValue); + + static void s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext); + void QueueUpdateDisplay (unsigned msec); + void UpdateDisplay (); + void ShowEncoderDisplay (); + void ShowValueDisplay (); + + void UpdateEncoder (uint8_t ucEncID, uint8_t ucValue); + void UpdateEncoders (); + void UpdateTGColors (); + void UpdateMonoColor (); + void UpdatePortamentoColor (); + void UpdateATColor (u8 ucAT); + void UpdateChanGroups (); + + void SetPadColor (TBankID BankID, TPadID PadID, u8 state); + void SetPadColor (TBankID BankID, TPadID PadID, u8 state, u8 state2); + void SetPadColor (TBankID BankID, TPadID PadID, CColor color, u8 state); + void SetPadColor (TBankID BankID, TPadID PadID, CColor color); + + void SetChannelAT (u8 ucValue); + void SetVoice (u8 ucChannel, u8 ucVoice); + void SetAlgorithm (u8 ucChannel, u8 ucAlgorithm); + void SetEncoder (u8 ucChannel, u8 ucEncID, u8 ucVoice); + void ToggleMonoMode (u8 ucChannel); + void TogglePortamentoGlisssando (u8 ucChannel); + void ToggleTG (u8 ucTG); + void SelectTG (u8 ucTG); + void SelectChanTG (u8 ucTG); + + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + bool m_bDisableEncoderUpdate = false; + + CUIMenu::TCPageType m_encoderPageType = CUIMenu::PageMain; + u8 m_ucEncoderPage = 0; + u8 m_ucEncoderOP = 0; + u8 m_ucEncoderTG = 0; + CUIMenu::TCParameterInfo *m_pEncoders; + + enum DisplayState { + DisplayMenu, + DisplayEncoder, + DisplayValues, + }; + DisplayState m_DisplayState = DisplayMenu; + + static constexpr size_t nEncoder = 8; + static constexpr size_t nFader = 4; + + CUIMenu::TCParameterInfo m_pMainEncoders[1 + 0 + 2 + 5 + 3 + 22][nEncoder + nFader] = { + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCutoff}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterResonance}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX1Send, "FX1Send", "FX1"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX2Send, "FX2Send", "FX2"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPortamentoTime}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterProgram}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ToString=to_percent}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterVolume, "Master Vol", "MVo", .ToString=to_percent}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=1, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=2, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=3, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ChG=4, .ToString=to_percent}, + }, + /*{ + // Effect Master EQ + }, + { + // Effect Limiter + },*/ + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn1", .TG=1, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn2", .TG=2, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn3", .TG=3, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn4", .TG=4, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt1", .TG=1}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt2", .TG=2}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt3", .TG=3}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt4", .TG=4}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=1, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=2, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=3, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=4, .ToString=to_percent}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn5", .TG=5, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn6", .TG=6, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn7", .TG=7, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .Short="Pn8", .TG=8, .ToString=to_string}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt5", .TG=5}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt6", .TG=6}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt7", .TG=7}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune, .Short="Dt8", .TG=8}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=5, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=6, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=7, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .TG=8, .ToString=to_percent}, + }, + }; + + CUIMenu::TCParameterInfo m_pEffectEncoders[0][nEncoder + nFader] = { + /*{ + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQLow, "MaEQ Low"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQMid, "MaEQ Mid"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQHigh, "MaEQ High"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQGain, "MaEQ Gain"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQLowMidFreq, "MaEQ LowMid"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQMidHighFreq, "MaEQ MidHigh"}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterNone}, + + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQLow, "MaEQ Low"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQMid, "MaEQ Mid"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQHigh, "MaEQ High"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterEQGain, "MaEQ Gain"}, + }, + { + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorEnable, "Master Compressor"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorPreGain, "MaCR Pre Gain"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorAttack, "MaCR Attack"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorRelease, "MaCR Release"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorThresh, "MaCR Thresh"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorRatio, "MaCR Ratio"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorHPFilterEnable, "MaCR HP Filter"}, + {CUIMenu::ParameterNone}, + + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorPreGain, "MaCR Pre Gain"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorAttack, "MaCR Attack"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorRelease, "MaCR Release"}, + {CUIMenu::ParameterGlobal, CMiniDexed::ParameterMasterCompressorThresh, "MaCR Thresh"}, + },*/ + }; + + CUIMenu::TCParameterInfo m_pTGEncoders[6 + 3 + 22][nEncoder + nFader] = { + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCutoff}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterResonance}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX1Send, "FX1Send", "FX1"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX2Send, "FX2Send", "FX2"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMasterTune}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPortamentoTime}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ToString=to_percent}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPan, .ToString=to_string}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCutoff}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX1Send, "FX1Send", "FX1"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFX2Send, "FX2Send", "FX2"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterVolume, .ToString=to_percent}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMIDIChannel}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterProgram}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPitchBendRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPortamentoGlissando}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMonoMode}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterPitchBendStep}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQLow, "TGEQ Low"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQMid, "TGEQ Mid"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQHigh, "TGEQ High"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQGain, "TGEQ Gain"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQLowMidFreq, "TGEQ LowMid"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQMidHighFreq, "TGEQ MidHigh"}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterNone}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQLow, "TGEQ Low"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQMid, "TGEQ Mid"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQHigh, "TGEQ High"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterEQGain, "TGEQ Gain"}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorEnable, "Compressor"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorPreGain, "Pre Gain"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorMakeupGain, "Makeup Gain"}, + {CUIMenu::ParameterNone}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorAttack, "Attack"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorRelease, "Release"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorThresh, "Thresh"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorRatio, "Ratio"}, + + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorPreGain, "Pre Gain"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorAttack, "Attack"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorRelease, "Release"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterCompressorThresh, "Thresh"}, + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWPitch, "MW Pitch", "MWP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCPitch, "FC Pitch", "FCP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWEGBias, "MW EG Bias", "MWEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterMWAmplitude, "MW Amp", "MWA"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCEGBias, "FC EG Bias", "FCEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterFCAmplitude, "FC Amp", "FCA"}, + + }, + { + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCPitch, "BC Pitch", "BCP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATRange}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATPitch, "AT Pitch", "ATP"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCEGBias, "BC EG Bias", "BCEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterBCAmplitude, "BC Amp", "BCA"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATEGBias, "AT EG Bias", "ATEB"}, + {CUIMenu::ParameterTG, CMiniDexed::TGParameterATAmplitude, "AT Amp", "ATA"}, + }, + }; + + CUIMenu::TCParameterInfo m_pVoiceEncoders[3 + 22][nEncoder + nFader] = { + { + {CUIMenu::ParameterVoice, DEXED_ALGORITHM}, + {CUIMenu::ParameterVoice, DEXED_FEEDBACK}, + {CUIMenu::ParameterVoice, DEXED_TRANSPOSE}, + }, + { + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R1}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R2}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R3}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_R4}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L1}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L2}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L3}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L4}, + + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L1}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L2}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L3}, + {CUIMenu::ParameterVoice, DEXED_PITCH_EG_L4}, + }, + { + {CUIMenu::ParameterVoice, DEXED_OSC_KEY_SYNC}, + {CUIMenu::ParameterVoice, DEXED_LFO_SPEED}, + {CUIMenu::ParameterVoice, DEXED_LFO_PITCH_MOD_SENS}, + {CUIMenu::ParameterVoice, DEXED_LFO_PITCH_MOD_DEP}, + {CUIMenu::ParameterVoice, DEXED_LFO_SYNC}, + {CUIMenu::ParameterVoice, DEXED_LFO_DELAY}, + {CUIMenu::ParameterVoice, DEXED_LFO_WAVE}, + {CUIMenu::ParameterVoice, DEXED_LFO_AMP_MOD_DEP}, + }, + }; + + CUIMenu::TCParameterInfo m_pOPEncoders[3][nEncoder + nFader] = { + { + {CUIMenu::ParameterOP, DEXED_OP_OUTPUT_LEV}, + {CUIMenu::ParameterOP, DEXED_OP_FREQ_COARSE}, + {CUIMenu::ParameterOP, DEXED_OP_FREQ_FINE}, + {CUIMenu::ParameterOP, DEXED_OP_OSC_DETUNE}, + {CUIMenu::ParameterOP, DEXED_OP_OSC_MODE}, + {CUIMenu::ParameterOP, DEXED_OP_ENABLE}, + }, + { + {CUIMenu::ParameterOP, DEXED_OP_EG_R1}, + {CUIMenu::ParameterOP, DEXED_OP_EG_R2}, + {CUIMenu::ParameterOP, DEXED_OP_EG_R3}, + {CUIMenu::ParameterOP, DEXED_OP_EG_R4}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L1}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L2}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L3}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L4}, + + {CUIMenu::ParameterOP, DEXED_OP_EG_L1}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L2}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L3}, + {CUIMenu::ParameterOP, DEXED_OP_EG_L4}, + }, + { + {CUIMenu::ParameterOP, DEXED_OP_LEV_SCL_BRK_PT}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_LEFT_DEPTH}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_RGHT_DEPTH}, + {CUIMenu::ParameterOP, DEXED_OP_AMP_MOD_SENS}, + {CUIMenu::ParameterOP, DEXED_OP_OSC_RATE_SCALE}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_LEFT_CURVE}, + {CUIMenu::ParameterOP, DEXED_OP_SCL_RGHT_CURVE}, + {CUIMenu::ParameterOP, DEXED_OP_KEY_VEL_SENS}, + }, + }; + + TKernelTimerHandle m_DisplayTimer = 0; + + u8 m_ucFirstTG = 0; + + CColor m_PadColorCache[8]; + CColor m_TGColorCache[8]; + + u8 m_EncoderCache[nEncoder]; + + u8 m_ChanGroups[nFader]; + + const uint8_t m_pEncoder[3] = {0x04, 0x02, 0x60}; + TMIDIRoute m_pRouteMap[75] = { + {0, 0, MIDI_CONTROL_CHANGE, 14, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_0, 0xFF}, // Fader1 + {0, 0, MIDI_CONTROL_CHANGE, 15, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_1, 0xFF}, // Fader2 + {0, 0, MIDI_CONTROL_CHANGE, 30, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_2, 0xFF}, // Fader3 + {0, 0, MIDI_CONTROL_CHANGE, 31, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_FADER_3, 0xFF}, // Fader4 + + {0, 0, MIDI_CONTROL_CHANGE, 118, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {0, 0, MIDI_CONTROL_CHANGE, 118, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 118, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {0, 0, MIDI_CONTROL_CHANGE, 119, 0x7F, .bSkip=true}, // Shift + Main knob click + {0, 0, MIDI_CONTROL_CHANGE, 119, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_HOME, 0}, + + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {0, 0, MIDI_CONTROL_CHANGE, 28, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + {0, 0, MIDI_CONTROL_CHANGE, 27, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Shift + {0, 0, MIDI_CONTROL_CHANGE, 27, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_VALUES_TOGGLE, 0xFF, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 27, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_DISPLAY_MODE_TOGGLE, 0xFF, .bGroup=true}, + + {0, 0, MIDI_CONTROL_CHANGE, 86, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_0, 0xFF}, // Knob1 + {0, 0, MIDI_CONTROL_CHANGE, 87, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_1, 0xFF}, // Knob2 + {0, 0, MIDI_CONTROL_CHANGE, 89, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_2, 0xFF}, // Knob3 + {0, 0, MIDI_CONTROL_CHANGE, 90, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_3, 0xFF}, // Knob4 + {0, 0, MIDI_CONTROL_CHANGE, 110, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_4, 0xFF}, // Knob5 + {0, 0, MIDI_CONTROL_CHANGE, 111, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_5, 0xFF}, // Knob6 + {0, 0, MIDI_CONTROL_CHANGE, 116, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_6, 0xFF}, // Knob7 + {0, 0, MIDI_CONTROL_CHANGE, 117, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_7, 0xFF}, // Knob8 + + {0, 9, MIDI_NOTE_ON, 36, 0xFF, .bSkip=true}, // BankA Pad1 + {0, 9, MIDI_NOTE_OFF, 36, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_MONO, 0x7F}, + + {0, 9, MIDI_NOTE_ON, 37, 0xFF, .bSkip=true, .bGroupHead=true}, // BankA Pad2 + {0, 9, MIDI_NOTE_OFF, 37, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO, 0x7F, .bToggle=true, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 37, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_PORTA_GLISS, 0x7F, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 38, 0xFF, .bSkip=true}, // BankA Pad3 + {0, 9, MIDI_NOTE_OFF, 38, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SOSTENUTO, 0x7F, .bToggle=true}, + + {0, 9, MIDI_NOTE_ON, 39, 0xFF, .bSkip=true}, // BankA Pad4 + {0, 9, MIDI_NOTE_OFF, 39, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SUSTAIN, 0x7F, .bToggle=true}, + + {0, 9, MIDI_NOTE_ON, 40, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_ALL_SOUND_OFF, 0x7F}, // BankA Pad5 + {0, 9, MIDI_NOTE_OFF, 40, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_ALL_SOUND_OFF, 0x00}, + + {0, 9, MIDI_NOTE_ON, 41, 0xFF, .bSkip=true}, // BankA Pad6 + {0, 9, MIDI_NOTE_OFF, 41, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_HOLD2, 0x7F, .bToggle=true}, + + {0, 9, MIDI_NOTE_ON, 42, 0xFF, .bSkip=true}, // BankA Pad7 + {0, 9, MIDI_NOTE_OFF, 42, 0xFF, .bSkip=true}, + + {0, 9, MIDI_NOTE_ON, 43, 0xFF, .bSkip=true}, // BankA Pad8 + {0, 9, MIDI_NOTE_OFF, 43, 0xFF, 0, MIDI_CHANNEL_AFTERTOUCH, 0x00, 0xFF}, + {0, 9, MIDI_AFTERTOUCH, 43, 0xFF, 0, MIDI_CHANNEL_AFTERTOUCH, TMIDIRoute::P2, 0xFF}, + + {0, 9, MIDI_NOTE_ON, 44, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad1 + {0, 9, MIDI_NOTE_OFF, 44, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 44, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 0, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 44, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 0, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 45, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad2 + {0, 9, MIDI_NOTE_OFF, 45, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 1, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 45, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 1, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 45, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 1, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 46, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad3 + {0, 9, MIDI_NOTE_OFF, 46, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 2, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 46, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 2, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 46, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 2, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 47, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad4 + {0, 9, MIDI_NOTE_OFF, 47, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 3, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 47, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 3, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 47, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 3, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 48, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad5 + {0, 9, MIDI_NOTE_OFF, 48, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 4, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 48, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 4, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 48, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 4, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 49, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad6 + {0, 9, MIDI_NOTE_OFF, 49, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 5, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 49, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 5, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 49, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 5, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 50, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad7 + {0, 9, MIDI_NOTE_OFF, 50, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 6, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 50, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 6, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 50, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 6, .bGroup=true}, + + {0, 9, MIDI_NOTE_ON, 51, 0xFF, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // BankB Pad8 + {0, 9, MIDI_NOTE_OFF, 51, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 7, .bGroup=true}, + {0, 9, MIDI_NOTE_OFF, 51, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_CHAN_TG, 7, .bGroup=true}, + {0, 9, MIDI_AFTERTOUCH, 51, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 7, .bGroup=true}, + + {0xFF}, // Sentinel + }; +}; + +CMiniLab3DawConnection::CMiniLab3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x6A, 0x21, 0xF7}; + + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On MiniLab 3", 0, 0); + + SetPadColor (BankA, MonoPad, 0); + SetPadColor (BankA, PortamentoPad, 0); + SetPadColor (BankA, SostenutoPad, 0); + SetPadColor (BankA, SustainPad, 0); + SetPadColor (BankA, SoundOffPad, 0); + SetPadColor (BankA, HoldPad, 0); + SetPadColor (BankA, TBDPad7, 0); + UpdateATColor (0); + + for (unsigned vIdx = 3,i = 0; i < ARRAY_LENGTH (m_pOPEncoders); ++i) + for (unsigned j = 0; j < nEncoder; ++j) + { + CUIMenu::TCParameterInfo *pInfo = &m_pOPEncoders[i][j]; + if (!pInfo->Type) + continue; + + for (unsigned k = 0; k < 6; ++k) + m_pVoiceEncoders[vIdx][k] = {pInfo->Type, pInfo->Parameter, .OP=static_cast(k+1)}; + + m_pVoiceEncoders[vIdx][7] = {pInfo->Type, pInfo->Parameter, .OP=AllOP}; + + vIdx++; + } + + assert (sizeof m_pTGEncoders == sizeof *m_pTGEncoders * 6 + sizeof m_pVoiceEncoders); + memcpy (m_pTGEncoders + 6, m_pVoiceEncoders, sizeof m_pVoiceEncoders); + + assert (sizeof m_pMainEncoders == sizeof *m_pMainEncoders * 1 + sizeof m_pEffectEncoders + sizeof *m_pMainEncoders * 2 + sizeof *m_pTGEncoders * 5 + sizeof m_pVoiceEncoders); + memcpy (m_pMainEncoders + 1, m_pEffectEncoders, sizeof m_pEffectEncoders); + memcpy (m_pMainEncoders + 5, m_pTGEncoders + 1, sizeof *m_pTGEncoders * 5); + memcpy (m_pMainEncoders + 10, m_pVoiceEncoders, sizeof m_pVoiceEncoders); + + for (unsigned i = 0; i < ARRAY_LENGTH (m_pMainEncoders); ++i) + m_pUI->GetParameterInfos (m_pMainEncoders[i], ARRAY_LENGTH (m_pMainEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pTGEncoders); ++i) + m_pUI->GetParameterInfos (m_pTGEncoders[i], ARRAY_LENGTH (m_pTGEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pEffectEncoders); ++i) + m_pUI->GetParameterInfos (m_pEffectEncoders[i], ARRAY_LENGTH (m_pEffectEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pVoiceEncoders); ++i) + m_pUI->GetParameterInfos (m_pVoiceEncoders[i], ARRAY_LENGTH (m_pVoiceEncoders[i])); + for (unsigned i = 0; i < ARRAY_LENGTH (m_pOPEncoders); ++i) + m_pUI->GetParameterInfos (m_pOPEncoders[i], ARRAY_LENGTH (m_pOPEncoders[i])); + + + memset (m_PadColorCache, 0xFF, sizeof (m_PadColorCache)); + memset (m_TGColorCache, 0xFF, sizeof (m_TGColorCache)); + memset (m_EncoderCache, 0xFF, sizeof (m_EncoderCache)); + + + UpdateMenu (m_encoderPageType, m_ucEncoderPage, m_ucEncoderOP, m_ucEncoderTG); + QueueUpdateDisplay (nDefaultDisplayUpdateDelay); +} + +void CMiniLab3DawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + const uint8_t page = bArrowDown == bArrowUp ? 0x11 : bArrowDown ? 0x10 : 0x00; + const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x1f, 0x06, 0x00, 0x00, page, 0x00, 0x11, 0x00, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, true, false, pMenu, pParam, pValue, false, false, false); +} + +void CMiniLab3DawConnection::DisplayWriteSimple (const char *pMenu, const char *pParam, const char *pValue) +{ + const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, true, false, pMenu, pParam, pValue, false, false, false); +} + +void CMiniLab3DawConnection::QueueUpdateDisplay (unsigned msec) +{ + if (m_DisplayTimer) + CTimer::Get ()->CancelKernelTimer (m_DisplayTimer); + m_DisplayTimer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (msec), s_UpdateDisplay, this, NULL); +} + +void CMiniLab3DawConnection::s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + assert (pParam != NULL); + static_cast(pParam)->UpdateDisplay (); +} + +void CMiniLab3DawConnection::UpdateDisplay () +{ + switch (m_DisplayState) + { + case DisplayMenu: + m_pUI->MIDIEventHandler (CUIMenu::MenuEventUpdate); + break; + case DisplayEncoder: + ShowEncoderDisplay (); + break; + case DisplayValues: + ShowValueDisplay (); + break; + } +} + +void CMiniLab3DawConnection::ShowEncoderDisplay () +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01}; + std::string pParam = ""; + std::string pValue = ""; + for (unsigned i = 0; i < nEncoder; ++i) + { + const char *pShort = m_pEncoders[i].Short ?: "..."; + if (i < 4) + pParam = pParam + pShort + " "; + else + pValue = pValue + pShort + " "; + } + + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, false, false, "", pParam.c_str(), pValue.c_str(), false, false, false); +} + +static int GetParameterValue (CMiniDexed *pSynthesizer, CUIMenu::TCParameterInfo *pInfo, uint8_t ucOP, uint8_t ucTG) +{ + switch (pInfo->Type) + { + case CUIMenu::ParameterGlobal: + return pSynthesizer->GetParameter (static_cast(pInfo->Parameter)); + break; + case CUIMenu::ParameterTG: + return pSynthesizer->GetTGParameter (static_cast(pInfo->Parameter), ucTG); + break; + case CUIMenu::ParameterVoice: + return pSynthesizer->GetVoiceParameter (pInfo->Parameter, CMiniDexed::NoOP, ucTG); + break; + case CUIMenu::ParameterOP: + return pSynthesizer->GetVoiceParameter (pInfo->Parameter, ucOP, ucTG); + break; + default: + return 0; + break; + } +} + +static std::string GetParameterValueStr (CMiniDexed *pSynthesizer, CUIMenu::TCParameterInfo *pInfo, uint8_t ucOP, uint8_t ucTG) +{ + if (pInfo->Type == CUIMenu::ParameterNone) + return "..."; + int value = GetParameterValue (pSynthesizer, pInfo, ucOP, ucTG); + if (pInfo->ToString) + return pInfo->ToString (value, 0); + return std::to_string (value); +} + + +void CMiniLab3DawConnection::ShowValueDisplay () +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x1f, 0x07, 0x01, 0x02, 0x02, 0x01, 0x00, 0x01}; + std::string pParam = ""; + std::string pValue = ""; + + for (unsigned i = 0; i < nEncoder; ++i) + { + CUIMenu::TCParameterInfo *enc = &m_pEncoders[i]; + uint8_t ucTG = enc->TG ? enc->TG - 1 : m_ucEncoderTG ? m_ucEncoderTG - 1 : m_ucFirstTG; + uint8_t ucOP = enc->OP ? enc->OP - 1 : m_ucEncoderOP; + if (enc->OP == AllOP) + ucOP = 0; + + std::string sValue = GetParameterValueStr (m_pSynthesizer, enc, ucOP, ucTG); + + if (i < 4) + pParam = pParam + sValue + " "; + else + pValue = pValue + sValue + " "; + } + + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, false, false, "", pParam.c_str(), pValue.c_str(), false, false, false); +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, u8 state) +{ + SetPadColor (BankID, PadID, padColors[PadID], state); +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, u8 state, u8 state2) +{ + SetPadColor (BankID, PadID, state2 ? altPadColors[PadID] : padColors[PadID], state); +} + +static CColor darken(CColor color, u8 enabled) +{ + if (!enabled) + { + color.r /= 32; + color.g /= 32; + color.b /= 32; + } + + return color; +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, CColor color, u8 state) +{ + SetPadColor (BankID, PadID, darken (color, state)); +} + +void CMiniLab3DawConnection::SetPadColor (TBankID BankID, TPadID PadID, CColor color) +{ + if (BankID == BankA && m_PadColorCache[PadID] == color) + return; + + const uint8_t pSetPadColor[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x02, 0x16, (uint8_t)(PadID + BankID), color.r, color.g, color.b, 0xF7}; + m_pKeyboard->Send (pSetPadColor, sizeof pSetPadColor, 0); + + if (BankID == BankA) + m_PadColorCache[PadID] = color; +} + +void CMiniLab3DawConnection::UpdateEncoder (uint8_t ucEncID, uint8_t ucValue) +{ + uint8_t pUpdateEncoder[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x21, 0x10, 0x00, ucEncID+=7, 0x00, ucValue, 0xF7}; + m_pKeyboard->Send (pUpdateEncoder, sizeof pUpdateEncoder, 0); +} + +void CMiniLab3DawConnection::UpdateTGColors () +{ + bool need_update = false; + CColor colors[8]; + uint8_t numTG = std::min(m_pConfig->GetToneGenerators(), 8u); + + for (unsigned i = 0; i < numTG; ++i) + { + u8 ch = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + u8 enabled = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i); + + colors[i] = darken (chColors[ch], enabled); + + if (m_TGColorCache[i] != colors[i]) + need_update = true; + } + + if (!need_update) + return; + + for (unsigned i = 0; i < numTG; ++i) + { + SetPadColor (BankB, (TPadID)i, colors[i]); + m_TGColorCache[i] = colors[i]; + } +} + +void CMiniLab3DawConnection::UpdateMonoColor () +{ + SetPadColor (BankA, MonoPad, m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG)); +} + +void CMiniLab3DawConnection::UpdatePortamentoColor () +{ + u8 mode = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoMode, m_ucFirstTG); + u8 mode2 = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG); + SetPadColor (BankA, PortamentoPad, mode, mode2); +} + +void CMiniLab3DawConnection::UpdateATColor (u8 ucAT) +{ + u8 c = ucAT ?: 1; + SetPadColor (BankA, ATPad, CColor {c, c, c}); +} + +void CMiniLab3DawConnection::UpdateEncoders () +{ + bool need_update = false; + u8 values[nEncoder]; + + if (m_bDisableEncoderUpdate) + return; + + for (unsigned i = 0; i < nEncoder; ++i) + { + CUIMenu::TCParameterInfo *enc = &m_pEncoders[i]; + u8 ucTG = enc->TG ? enc->TG - 1 : m_ucEncoderTG ? m_ucEncoderTG - 1 : m_ucFirstTG; + u8 ucOP = enc->OP ? enc->OP - 1 : m_ucEncoderOP; + if (enc->OP == AllOP) + ucOP = 0; + int value; + + switch (enc->Type) + { + case CUIMenu::ParameterGlobal: + value = m_pSynthesizer->GetParameter (static_cast(enc->Parameter)); + break; + case CUIMenu::ParameterTG: + value = m_pSynthesizer->GetTGParameter (static_cast(enc->Parameter), ucTG); + break; + case CUIMenu::ParameterVoice: + value = m_pSynthesizer->GetVoiceParameter (enc->Parameter, CMiniDexed::NoOP, ucTG); + break; + case CUIMenu::ParameterOP: + value = m_pSynthesizer->GetVoiceParameter (enc->Parameter, ucOP, ucTG); + break; + default: + continue; + } + values[i] = mapfloatr (value, enc->Min, enc->Max, 0, 127); + if (values[i] != m_EncoderCache[i]) + need_update = true; + } + + if (!need_update) + return; + + for (unsigned i = 0; i < nEncoder; ++i) + { + UpdateEncoder (i, values[i]); + m_EncoderCache[i] = values[i]; + } +} + +void CMiniLab3DawConnection::UpdateChanGroups () +{ + memset (m_ChanGroups, CMIDIDevice::Disabled, sizeof m_ChanGroups); + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + int channel = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + + if (channel == CMIDIDevice::ChannelUnknown || channel == CMIDIDevice::Disabled) + continue; + + if (channel == CMIDIDevice::OmniMode) + channel = 0; + + for (unsigned i = 0; i < sizeof m_ChanGroups; ++i) + { + if (m_ChanGroups[i] == channel) + break; + + if (m_ChanGroups[i] == CMIDIDevice::Disabled) { + m_ChanGroups[i] = channel; + break; + } + } + } +} + +void CMiniLab3DawConnection::UpdateState () +{ + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + u8 ucChannel = m_pKeyboard->GetChannel (i); + + if (ucChannel == CMIDIDevice::ChannelUnknown || ucChannel == CMIDIDevice::Disabled) + continue; + + if (ucChannel == CMIDIDevice::OmniMode) + ucChannel = 0; + + for (TMIDIRoute *r = m_pRouteMap; r->ucSCable != 0xFF; r++) + r->ucDCh = ucChannel; + + m_ucFirstTG = i; + + break; + } + + UpdateEncoders (); + + UpdateMonoColor (); + // TODO change the MIDIRouteMap's value also + UpdatePortamentoColor (); + + UpdateTGColors (); + + UpdateChanGroups (); +} + +void CMiniLab3DawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + m_encoderPageType = Type; + m_ucEncoderOP = ucOP; + m_ucEncoderTG = ucTG; + + switch (Type) + { + case CUIMenu::PageMain: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pMainEncoders) - 1); + m_pEncoders = m_pMainEncoders[m_ucEncoderPage]; + m_ucEncoderTG = 0; // 0 -> first active TG + break; + case CUIMenu::PageTG: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pTGEncoders) - 1); + m_pEncoders = m_pTGEncoders[m_ucEncoderPage]; + break; + //case CUIMenu::PageEffect: + // m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pEffectEncoders) - 1); + // m_pEncoders = m_pEffectEncoders[m_ucEncoderPage]; + // break; + case CUIMenu::PageVoice: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pVoiceEncoders) - 1); + m_pEncoders = m_pVoiceEncoders[m_ucEncoderPage]; + break; + case CUIMenu::PageOP: + m_ucEncoderPage = constrain (ucPage, 0, (s8)ARRAY_LENGTH (m_pOPEncoders) - 1); + m_pEncoders = m_pOPEncoders[m_ucEncoderPage]; + break; + default: + assert (false); + } + + UpdateState (); +} + +void CMiniLab3DawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + unsigned nDisplayUpdateDelay = nDefaultDisplayUpdateDelay; + switch (ucType) + { + case MIDI_CONTROL_CHANGE: + ArturiaShowNewCCValue (m_pKeyboard, m_pEncoder, ucChannel, ucP1, ucP2); + + switch (ucP1) + { + case MIDI_CC_PORTAMENTO: + UpdatePortamentoColor (); + break; + case MIDI_CC_SOSTENUTO: + SetPadColor (BankA, SostenutoPad, ucP2); + break; + case MIDI_CC_HOLD2: + SetPadColor (BankA, HoldPad, ucP2); + break; + case MIDI_CC_SUSTAIN: + SetPadColor (BankA, SustainPad, ucP2); + break; + case MIDI_CC_ALL_SOUND_OFF: + SetPadColor (BankA, SoundOffPad, ucP2); + break; + } + break; + case MIDI_DAW_CHANGE: + switch (m_DisplayState) + { + case DisplayMenu: + HandleMenuEvents (m_pUI, ucP1); + break; + case DisplayEncoder: + switch (ucP1) + { + case MIDI_DAW_MENU_PREV: + UpdateMenu (m_encoderPageType, m_ucEncoderPage - 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + break; + case MIDI_DAW_MENU_NEXT: + UpdateMenu (m_encoderPageType, m_ucEncoderPage + 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + break; + case MIDI_DAW_ENC_VALUES_TOGGLE: + m_DisplayState = DisplayValues; + UpdateDisplay (); + break; + } + break; + case DisplayValues: + switch (ucP1) + { + case MIDI_DAW_MENU_PREV: + UpdateMenu (m_encoderPageType, m_ucEncoderPage - 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + nDisplayUpdateDelay = 500; + break; + case MIDI_DAW_MENU_NEXT: + UpdateMenu (m_encoderPageType, m_ucEncoderPage + 1, m_ucEncoderOP, m_ucEncoderTG); + ShowEncoderDisplay (); + nDisplayUpdateDelay = 500; + break; + case MIDI_DAW_ENC_VALUES_TOGGLE: + m_DisplayState = DisplayEncoder; + UpdateDisplay (); + break; + } + break; + } + + switch (ucP1) + { + case MIDI_DAW_VOICE: + SetVoice (ucChannel, ucP2); + break; + case MIDI_DAW_TOGGLE_MONO: + ToggleMonoMode (ucChannel); + break; + case MIDI_DAW_TOGGLE_PORTA_GLISS: + TogglePortamentoGlisssando (ucChannel); + break; + case MIDI_DAW_TOGGLE_TG: + ToggleTG (ucP2); + break; + case MIDI_DAW_SELECT_TG: + SelectTG (ucP2); + break; + case MIDI_DAW_SELECT_CHAN_TG: + SelectChanTG (ucP2); + break; + case MIDI_DAW_DISPLAY_MODE_TOGGLE: + m_DisplayState = m_DisplayState != DisplayMenu ? DisplayMenu : DisplayEncoder; + UpdateDisplay (); + break; + case MIDI_DAW_ENC_0: + case MIDI_DAW_ENC_1: + case MIDI_DAW_ENC_2: + case MIDI_DAW_ENC_3: + case MIDI_DAW_ENC_4: + case MIDI_DAW_ENC_5: + case MIDI_DAW_ENC_6: + case MIDI_DAW_ENC_7: + SetEncoder (ucChannel, ucP1 - MIDI_DAW_ENC_0, ucP2); + break; + case MIDI_DAW_FADER_0: + case MIDI_DAW_FADER_1: + case MIDI_DAW_FADER_2: + case MIDI_DAW_FADER_3: + SetEncoder (ucChannel, ucP1 - MIDI_DAW_FADER_0 + 8, ucP2); + break; + } + break; + case MIDI_CHANNEL_AFTERTOUCH: + SetChannelAT (ucP1); + break; + } + QueueUpdateDisplay (nDisplayUpdateDelay); +} + +void CMiniLab3DawConnection::SetChannelAT (u8 ucValue) +{ + char line2[LINELEN]; + snprintf(line2, LINELEN, "%d", ucValue); + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, ucValue, "Channel AT", line2); + + UpdateATColor (ucValue); +} + +void CMiniLab3DawConnection::SetVoice (u8 ucChannel, u8 ucVoice) +{ + std::string line2; + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 || + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->ProgramChange (ucVoice, i); + if (line2.length() == 0) { + std::string sVoiceName = m_pSynthesizer->GetVoiceName (i); + if (sVoiceName.length() > 0) + line2 = std::to_string (ucVoice + 1) + "=" + sVoiceName; + } + } + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_KNOB, ucVoice, "Voice", line2.c_str()); +} + +void CMiniLab3DawConnection::SetEncoder (u8 ucChannel, u8 ucEncID, u8 ucValue) +{ + char line1[LINELEN]; + char line2[LINELEN]; + + CUIMenu::TCParameterInfo *encoder = &m_pEncoders[ucEncID]; + + if (encoder->Type == CUIMenu::ParameterNone) + return; + + int value = mapfloatr (ucValue, 0, 127, encoder->Min, encoder->Max); + u8 ucOP = encoder->OP ? encoder->OP - 1 : m_ucEncoderOP; + + // If we update the encoders during setup, we will get rounding problems, so disable it (not for faders) + if (ucEncID < nEncoder) + m_bDisableEncoderUpdate = true; + + u8 setted = false; + + if (encoder->Type == CUIMenu::ParameterGlobal) + { + m_pSynthesizer->SetParameter (static_cast(encoder->Parameter), value); + setted = true; + } + else + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0) + continue; + + if (m_ucEncoderTG && m_ucEncoderTG - 1u != i) + continue; + + if (m_ucEncoderTG == 0 && !encoder->ChG && !encoder->TG && + m_pKeyboard->GetChannel (i) != ucChannel && + m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode) + continue; + + if (encoder->ChG) + { + if (m_ChanGroups[encoder->ChG - 1u] == CMIDIDevice::Disabled) + continue; + + if (m_pKeyboard->GetChannel (i) != m_ChanGroups[encoder->ChG - 1u] && + m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode) + continue; + } + + if (encoder->TG && i != encoder->TG - 1u) + continue; + + switch (encoder->Type) + { + case CUIMenu::ParameterTG: + m_pSynthesizer->SetTGParameter (static_cast(encoder->Parameter), value, i); + break; + case CUIMenu::ParameterVoice: + m_pSynthesizer->SetVoiceParameter (encoder->Parameter, value, CMiniDexed::NoOP, i); + break; + case CUIMenu::ParameterOP: + for (unsigned j = 0; j < 6; ++j) + { + if (encoder->OP != AllOP && j != ucOP) + continue; + + m_pSynthesizer->SetVoiceParameter (encoder->Parameter, value, j, i); + } + break; + default: + break; + } + setted = true; + } + + m_bDisableEncoderUpdate = false; + + if (!setted) + return; + + if (encoder->ChG) + snprintf(line1, LINELEN, "Ch %d %s", m_ChanGroups[encoder->ChG - 1u] + 1, encoder->Name); + else if (encoder->TG) + snprintf(line1, LINELEN, "TG%d %s", encoder->TG, encoder->Name); + else + snprintf(line1, LINELEN, "%s", encoder->Name); + + if (encoder->ToString) + snprintf(line2, LINELEN, "%s", encoder->ToString(value, 0).c_str()); + else + snprintf(line2, LINELEN, "%d", value); + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, ucEncID < nEncoder ? CT_KNOB : CT_FADER, ucValue, line1, line2); +} + +void CMiniLab3DawConnection::ToggleMonoMode (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 || + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setMonoMode (ucValue, i); + } + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, ucValue, "Mono Mode", ucValue > 64 ? "On" : "Off"); + UpdateMonoColor (); +} + +void CMiniLab3DawConnection::TogglePortamentoGlisssando (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 && + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setPortamentoGlissando (ucValue, i); + } + + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, ucValue, "Porta Gliss", ucValue > 64 ? "On" : "Off"); + UpdatePortamentoColor (); +} + +void CMiniLab3DawConnection::ToggleTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 value = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, ucTG) ? 0x00 : 0x7F; + + m_pSynthesizer->setEnabled (value, ucTG); + m_pSynthesizer->panic (value, ucTG); + + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, value, line1, value > 64 ? "On" : "Off"); +} + +void CMiniLab3DawConnection::SelectTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 enabledOne = true; + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (i == ucTG) + continue; + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + enabledOne = false; + break; + } + } + + if (enabledOne) { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + m_pSynthesizer->setEnabled (true, i); + } + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, 0x7F, "TG All", "On"); + } else { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + if (i == ucTG) { + m_pSynthesizer->setEnabled (true, i); + } else { + m_pSynthesizer->setEnabled (false, i); + m_pSynthesizer->panic (false, i); + } + } + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, 0x7F, line1, "Selected"); + } +} + + +void CMiniLab3DawConnection::SelectChanTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 enabled = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, ucTG); + u8 channel = m_pKeyboard->GetChannel (ucTG); + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + if (m_pKeyboard->GetChannel (i) == channel) { + if (enabled) { + m_pSynthesizer->setEnabled (false, i); + m_pSynthesizer->panic (false, i); + } else { + m_pSynthesizer->setEnabled (true, i); + } + } + } + + snprintf(line1, LINELEN, "TGs on Ch %s", to_midi_channel(channel).c_str()); + + // this doesn't work well with Minilab 3 firmware 1.2.0 + // ArturiaDisplayInfoWrite (m_pKeyboard, m_pEncoder, CT_PAD, 0x7F, line1, enabled ? "Off" : "On"); + + DisplayWriteSimple (line1, "", enabled ? "Off" : "On"); +} + +class CKeyLabEs3DawConnection : public CDAWConnection +{ +public: + CKeyLabEs3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite ( const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + void UpdateEncoder (uint8_t ucEncID, uint8_t ucValue); + + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + const uint8_t m_pEncoder[3] = {0x04, 0x01, 0x60}; + TMIDIRoute m_pRouteMap[26] = { + {0, 0, MIDI_CONTROL_CHANGE, 117, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {0, 0, MIDI_CONTROL_CHANGE, 117, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 117, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {0, 0, MIDI_CONTROL_CHANGE, 44, 0x7F, .bSkip=true}, // Home + {0, 0, MIDI_CONTROL_CHANGE, 44, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_HOME, 0}, + + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {0, 0, MIDI_CONTROL_CHANGE, 116, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + {0, 0, MIDI_CONTROL_CHANGE, 105, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader1 + {0, 0, MIDI_CONTROL_CHANGE, 106, 0xFF, 1, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader2 + {0, 0, MIDI_CONTROL_CHANGE, 107, 0xFF, 2, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader3 + {0, 0, MIDI_CONTROL_CHANGE, 108, 0xFF, 3, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader4 + {0, 0, MIDI_CONTROL_CHANGE, 109, 0xFF, 4, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader5 + {0, 0, MIDI_CONTROL_CHANGE, 110, 0xFF, 5, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader6 + {0, 0, MIDI_CONTROL_CHANGE, 111, 0xFF, 6, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader7 + {0, 0, MIDI_CONTROL_CHANGE, 112, 0xFF, 7, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader8 + {0, 0, MIDI_CONTROL_CHANGE, 113, 0xFF, 8, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader9 + + {0, 0, MIDI_CONTROL_CHANGE, 96, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_FREQUENCY_CUTOFF, 0xFF}, // Knob1 + {0, 0, MIDI_CONTROL_CHANGE, 97, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_RESONANCE, 0xFF}, // Knob2 + {0, 0, MIDI_CONTROL_CHANGE, 98, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_EFFECT1_SEND, 0xFF}, // Knob3 + {0, 0, MIDI_CONTROL_CHANGE, 99, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_EFFECT2_SEND, 0xFF}, // Knob4 + {0, 0, MIDI_CONTROL_CHANGE, 100, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_DETUNE_LEVEL, 0xFF}, // Knob5 + {0, 0, MIDI_CONTROL_CHANGE, 101, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob6 + {0, 0, MIDI_CONTROL_CHANGE, 102, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO_TIME, 0xFF}, // Knob7 + // {0, 0, MIDI_CONTROL_CHANGE, 103, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob8 + // {0, 0, MIDI_CONTROL_CHANGE, 104, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob9 + {0xFF}, // Sentinel + }; +}; + +CKeyLabEs3DawConnection::CKeyLabEs3DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x6A, 0x21, 0xF7}; + + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On KeyLab 3 Essential", 0, 0); + + UpdateState (); +} + +void CKeyLabEs3DawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x01, 0x60, 0x12, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 18, true, true, pMenu, pParam, pValue, bArrowDown, bArrowUp, true); +} + +void CKeyLabEs3DawConnection::UpdateEncoder (uint8_t ucEncID, uint8_t ucValue) +{ + uint8_t pUpdateEncoder[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x0F, 0x40, ucEncID += 3, ucValue, 0xF7}; + m_pKeyboard->Send (pUpdateEncoder, sizeof pUpdateEncoder, 0); +} + +void CKeyLabEs3DawConnection::UpdateState () +{ + UpdateEncoder (0, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterCutoff, 0), 0, 99, 0, 127)); + UpdateEncoder (1, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterResonance, 0), 0, 99, 0, 127)); + UpdateEncoder (2, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterFX1Send, 0), 0, 99, 0, 127)); + UpdateEncoder (3, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterFX2Send, 0), 0, 99, 0, 127)); + UpdateEncoder (4, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMasterTune, 0), -99, 99, 1, 127)); + UpdateEncoder (5, m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPan, 0)); + UpdateEncoder (6, mapfloatr (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoTime, 0), 0, 99, 0, 127)); +} + +void CKeyLabEs3DawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + +} + +void CKeyLabEs3DawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + switch (ucType) + { + case MIDI_CONTROL_CHANGE: + ArturiaShowNewCCValue (m_pKeyboard, m_pEncoder, ucChannel, ucP1, ucP2); + break; + case MIDI_DAW_CHANGE: + HandleMenuEvents (m_pUI, ucP1); + break; + } +} + +class CKeyLab2DawConnection : public CDAWConnection +{ +public: + CKeyLab2DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + using TToString = CUIMenu::TToString; + struct TButton { + uint8_t sysexID; + const char* name; + uint8_t last_value; + }; + struct TRGBButton { + uint8_t sysexID; + CColor last_color = invalidColor; + }; + + bool m_bDisableStateUpdate = false; + + TButton m_MonoButton = {0x60, "Mono mode"}; + TButton m_PortamentoButton = {0x61, "Portamento"}; + TButton m_SostenutoButton = {0x62, "Sostenuto"}; + TButton m_SustainButton = {0x63, "Sustain"}; + TButton m_Hold2Button = {0x64, "Hold"}; + + TRGBButton m_SelButtons[8] = { + {0x22}, {0x23}, {0x24}, {0x25}, {0x26}, {0x27}, {0x28}, {0x29}, + }; + + static void s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext); + void QueueUpdateDisplay (unsigned msec); + void UpdateDisplay (); + void ShowNewValue (const char* name, u8 ucP2, TToString *ToString = NULL); + + void SetButtonColor (TRGBButton &button, CColor color); + + void SetButtonIntensity (TButton &button, uint8_t intensity); + void SetButtonLight (TButton &button, u8 state); + void SetButtonLight (TButton &button, u8 state, u8 state2); + + void UpdateVolumeFaders (); + void UpdateTGColors (); + void UpdateMonoColor (); + void UpdatePortamentoColor (); + void SetMasterVolume (u8 ucValue); + int SetParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TParameter parameter); + int SetTGParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TTGParameter parameter); + + void ToggleMonoMode (u8 ucChannel); + void TogglePortamentoGlisssando (u8 ucChannel); + + void ToggleTG (u8 ucTG); + void SelectTG (u8 ucTG); + + + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + TKernelTimerHandle m_DisplayTimer = 0; + + u8 m_ucFirstTG = 0; + + TMIDIRoute m_pRouteMap[58] = { + {1, 0, MIDI_PITCH_BEND, 0xFF, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader1 + {1, 1, MIDI_PITCH_BEND, 0xFF, 0xFF, 1, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader2 + {1, 2, MIDI_PITCH_BEND, 0xFF, 0xFF, 2, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader3 + {1, 3, MIDI_PITCH_BEND, 0xFF, 0xFF, 3, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader4 + {1, 4, MIDI_PITCH_BEND, 0xFF, 0xFF, 4, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader5 + {1, 5, MIDI_PITCH_BEND, 0xFF, 0xFF, 5, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader6 + {1, 6, MIDI_PITCH_BEND, 0xFF, 0xFF, 6, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader7 + {1, 7, MIDI_PITCH_BEND, 0xFF, 0xFF, 7, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader8 + {1, 8, MIDI_PITCH_BEND, 0xFF, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_MASTER_VOLUME, 0xFF}, // Fader9 + + {1, 0, MIDI_NOTE_ON, 0x54, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + //{1, 0, MIDI_NOTE_ON, 0x31, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Next + //{1, 0, MIDI_NOTE_ON, 0x30, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Prev + //{1, 0, MIDI_NOTE_ON, 0x21, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Bank? + + {1, 0, MIDI_NOTE_ON, 0x18, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select1 + {1, 0, MIDI_NOTE_ON, 0x18, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x18, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 0, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x19, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select2 + {1, 0, MIDI_NOTE_ON, 0x19, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 1, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x19, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 1, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1a, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select3 + {1, 0, MIDI_NOTE_ON, 0x1a, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 2, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1a, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 2, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1b, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select4 + {1, 0, MIDI_NOTE_ON, 0x1b, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 3, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1b, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 3, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1c, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select5 + {1, 0, MIDI_NOTE_ON, 0x1c, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 4, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1c, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 4, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1d, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select6 + {1, 0, MIDI_NOTE_ON, 0x1d, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 5, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1d, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 5, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1e, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select7 + {1, 0, MIDI_NOTE_ON, 0x1e, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 6, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1e, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 6, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, 0x1f, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Select8 + {1, 0, MIDI_NOTE_ON, 0x1f, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 7, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x1f, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_SELECT_TG, 7, .bGroup=true}, + + //{1, 0, MIDI_NOTE_ON, 0x33, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_TG, 0}, // Select9? + + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw08n15, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_MONO, 0x7f}, // Solo + + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw16n23, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Mute + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw16n23, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO, 0x7F, .bToggle=true, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw16n23, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_TOGGLE_PORTA_GLISS, 0x7F, .bGroup=true}, + + {1, 0, MIDI_NOTE_ON, TMIDIRoute::Betw00n07, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SOSTENUTO, 0x7F, .bToggle=true}, // Record + + {1, 0, MIDI_NOTE_ON, 0x4a, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_SUSTAIN, 0x7F, .bToggle=true}, // Read + + {1, 0, MIDI_NOTE_ON, 0x4b, 0x00, 0, MIDI_CONTROL_CHANGE, MIDI_CC_HOLD2, 0x7F, .bToggle=true}, // Write + + {1, 0, MIDI_CONTROL_CHANGE, 16, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_0, 0xFF}, // Knob1 + {1, 0, MIDI_CONTROL_CHANGE, 17, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_1, 0xFF}, // Knob2 + {1, 0, MIDI_CONTROL_CHANGE, 18, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_2, 0xFF}, // Knob3 + {1, 0, MIDI_CONTROL_CHANGE, 19, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_3, 0xFF}, // Knob4 + {1, 0, MIDI_CONTROL_CHANGE, 20, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_4, 0xFF}, // Knob5 + {1, 0, MIDI_CONTROL_CHANGE, 21, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_5, 0xFF}, // Knob6 + {1, 0, MIDI_CONTROL_CHANGE, 22, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_6, 0xFF}, // Knob7 + {1, 0, MIDI_CONTROL_CHANGE, 23, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_7, 0xFF}, // Knob8 + {1, 0, MIDI_CONTROL_CHANGE, 24, 0xFF, 0, MIDI_DAW_CHANGE, MIDI_DAW_ENC_8, 0xFF}, // Knob9 + {1, 0xFF, 0xFF, 0xFF, 0xFF, .bSkip = true}, // skip other messages on DAW cable + {0xFF}, // Sentinel + }; +}; + +/* +https://github.com/bitwig/bitwig-extensions/blob/da7d70e73cc055475d63ac6c7de17e69f89f4993/src/main/java/com/bitwig/extensions/controllers/arturia/keylab/mk2/ButtonId.java +SOLO(0x60, 0x08), +MUTE(0x61, 0x10), +RECORD_ARM(0x62, 0x00), +READ(0x63, 0x38), // 0x38 -> 0x4a +WRITE(0x64, 0x39), // 0x39 -> 0x4b + +SAVE(0x65,0x4A), +PUNCH_IN(0x66, 0x57), +PUNCH_OUT(0x67, 0x58), +METRO(0x68, 0x59), +UNDO(0x69, 0x51), + + +NEXT(0x1F, 0x31), +PREVIOUS(0x20, 0x30), +BANK(0x21, 0x21), +SELECT1(0x22, 0x18), +SELECT2(0x23, 0x19), +SELECT3(0x24, 0x1A), +SELECT4(0x25, 0x1B), +SELECT5(0x26, 0x1C), +SELECT6(0x27, 0x1D), +SELECT7(0x28, 0x1E), +SELECT8(0x29, 0x1F), +SELECT_MULTI(0x2A, 0x33); +*/ + +CKeyLab2DawConnection::CKeyLab2DawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x52, 0x00, 0xF7}; + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On KeyLab 2", 0, 0); + + SetButtonLight (m_SostenutoButton, 0); + SetButtonLight (m_SustainButton, 0); + SetButtonLight (m_Hold2Button, 0); + + UpdateState (); + QueueUpdateDisplay (nDefaultDisplayUpdateDelay); +} + +void CKeyLab2DawConnection::SetButtonColor (TRGBButton &button, CColor color) +{ + const uint8_t pSetButtonColor[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x16, button.sysexID, color.r, color.g, color.b, 0xF7}; + m_pKeyboard->Send (pSetButtonColor, sizeof pSetButtonColor, 0); +} + +void CKeyLab2DawConnection::SetButtonIntensity (TButton &button, uint8_t intensity) +{ + if (button.last_value == intensity) + return; + + const uint8_t pSetButtonIntensity[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x10, button.sysexID, intensity, 0xF7}; + m_pKeyboard->Send (pSetButtonIntensity, sizeof pSetButtonIntensity, 0); + + button.last_value = intensity; +} + +void CKeyLab2DawConnection::SetButtonLight (TButton &button, u8 state) +{ + SetButtonIntensity (button, state ? 0x7F : 0x04); +} + +void CKeyLab2DawConnection::SetButtonLight (TButton &button, u8 state, u8 state2) +{ + SetButtonIntensity (button, state ? state2 ? 0x7F : 0x3f : 0x04); +} + +void CKeyLab2DawConnection::UpdateTGColors () +{ + bool need_update = false; + CColor colors[8]; + uint8_t numTG = std::min(m_pConfig->GetToneGenerators(), 8u); + + for (unsigned i = 0; i < numTG; ++i) + { + u8 ch = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + u8 enabled = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i); + + colors[i] = chColors_kl2[ch]; + if (!enabled) + { + colors[i].r /= 8; + colors[i].g /= 8; + colors[i].b /= 8; + } + + if (m_SelButtons[i].last_color != colors[i]) + need_update = true; + } + + if (!need_update) + return; + + for (unsigned i = 0; i < numTG; ++i) + { + SetButtonColor (m_SelButtons[i], colors[i]); + m_SelButtons[i].last_color = colors[i]; + } +} + + +void CKeyLab2DawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x00, 0x60, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 16, true, true, pMenu, pParam, pValue, bArrowDown, bArrowUp, true); +} + +void CKeyLab2DawConnection::QueueUpdateDisplay (unsigned msec) +{ + if (m_DisplayTimer) + CTimer::Get ()->CancelKernelTimer (m_DisplayTimer); + m_DisplayTimer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (msec), s_UpdateDisplay, this, NULL); +} + +void CKeyLab2DawConnection::s_UpdateDisplay (TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + assert (pParam != NULL); + static_cast(pParam)->UpdateDisplay (); +} + +void CKeyLab2DawConnection::UpdateDisplay () +{ + m_pUI->MIDIEventHandler (CUIMenu::MenuEventUpdate); +} + +void CKeyLab2DawConnection::ShowNewValue (const char* name, u8 ucP2, CUIMenu::TToString *ToString) +{ + std::string line2 = ToString ? ToString(ucP2, 0) : std::to_string(ucP2); + DisplayWrite (name, "", line2.c_str(), 0, 0); +} + +void CKeyLab2DawConnection::UpdateState () +{ + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + u8 ucChannel = m_pKeyboard->GetChannel (i); + + if (ucChannel == CMIDIDevice::ChannelUnknown || ucChannel == CMIDIDevice::Disabled) + continue; + + if (ucChannel == CMIDIDevice::OmniMode) + ucChannel = 0; + + for (TMIDIRoute *r = m_pRouteMap; r->ucSCable != 0xFF; r++) + r->ucDCh = ucChannel; + + m_ucFirstTG = i; + + break; + } + + UpdateVolumeFaders (); + + if (m_bDisableStateUpdate) + return; + + UpdateTGColors (); + UpdateMonoColor (); + UpdatePortamentoColor (); +} + +void CKeyLab2DawConnection::UpdateVolumeFaders () +{ + u8 chan_map[8] = { + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + CMIDIDevice::TChannel::Disabled, + }; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + int channel = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMIDIChannel, i); + + if (channel == CMIDIDevice::ChannelUnknown || channel == CMIDIDevice::Disabled) + continue; + + if (channel == CMIDIDevice::OmniMode) + channel = 0; + + for (unsigned i = 0; i < sizeof chan_map; ++i) + { + if (chan_map[i] == channel) + break; + + if (chan_map[i] == CMIDIDevice::Disabled) { + chan_map[i] = channel; + break; + } + } + } + + for (unsigned i = 0; i < sizeof chan_map; ++i) + { + if (chan_map[i] == CMIDIDevice::Disabled) + m_pRouteMap[i].bSkip = true; + else { + m_pRouteMap[i].bSkip = false; + m_pRouteMap[i].ucDCh = chan_map[i]; + } + } +} + +void CKeyLab2DawConnection::ToggleTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 value = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, ucTG) ? 0x00 : 0x7F; + + m_pSynthesizer->setEnabled (value, ucTG); + m_pSynthesizer->panic (value, ucTG); + + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ShowNewValue (line1, value, to_on_off); +} + +void CKeyLab2DawConnection::SelectTG (u8 ucTG) +{ + char line1[LINELEN]; + + u8 enabledOne = true; + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (i == ucTG) + continue; + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i)) { + enabledOne = false; + break; + } + } + + m_bDisableStateUpdate = true; + + if (enabledOne) { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + m_pSynthesizer->setEnabled (true, i); + } + ShowNewValue ("TG All", 0x7f, to_on_off); + } else { + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) { + if (i == ucTG) { + m_pSynthesizer->setEnabled (true, i); + } else { + m_pSynthesizer->setEnabled (false, i); + m_pSynthesizer->panic (false, i); + } + } + snprintf(line1, LINELEN, "TG %d", ucTG + 1); + ShowNewValue (line1, 0x7f, to_selected); + } + + m_bDisableStateUpdate = false; + UpdateState (); +} + +void CKeyLab2DawConnection::ToggleMonoMode (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 || + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setMonoMode (ucValue, i); + } + + ShowNewValue ("Mono Mode", ucValue, to_on_off); +} + +void CKeyLab2DawConnection::SetMasterVolume (u8 ucValue) +{ + m_pSynthesizer->SetParameter (CMiniDexed::ParameterMasterVolume, ucValue); + ShowNewValue ("Master Volume", ucValue, to_percent); +} + +int CKeyLab2DawConnection::SetParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TParameter parameter) +{ + int ucValue = m_pSynthesizer->GetParameter (parameter); + + if (ucDiffValue < 64) // 1 2 3 + ucValue += ucDiffValue; + else // 65 66 67 + ucValue = std::max(0, ucValue - (ucDiffValue - 64)); + + m_pSynthesizer->SetParameter (parameter, ucValue); + + return m_pSynthesizer->GetParameter (parameter); +} + +int CKeyLab2DawConnection::SetTGParameter (u8 ucChannel, u8 ucDiffValue, CMiniDexed::TTGParameter parameter) +{ + int ucValue = m_pSynthesizer->GetTGParameter (parameter, m_ucFirstTG); + + if (ucDiffValue < 64) // 1 2 3 + ucValue += ucDiffValue; + else // 65 66 67 + ucValue = std::max(0, ucValue - (ucDiffValue - 64)); + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 && + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->SetTGParameter (parameter, ucValue, i); + } + + return m_pSynthesizer->GetTGParameter (parameter, m_ucFirstTG); +} + +void CKeyLab2DawConnection::UpdateMonoColor () +{ + SetButtonLight (m_MonoButton, m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterMonoMode, m_ucFirstTG)); +} + +void CKeyLab2DawConnection::UpdatePortamentoColor () +{ + u8 mode = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoMode, m_ucFirstTG); + u8 mode2 = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG); + SetButtonLight (m_PortamentoButton, mode, mode2); +} + +void CKeyLab2DawConnection::TogglePortamentoGlisssando (u8 ucChannel) +{ + u8 ucValue = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterPortamentoGlissando, m_ucFirstTG) ? 0x00 : 0x7F; + + for (unsigned i = 0; i < m_pConfig->GetToneGenerators(); ++i) + { + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, i) == 0 && + (m_pKeyboard->GetChannel (i) != ucChannel && m_pKeyboard->GetChannel (i) != CMIDIDevice::OmniMode)) + continue; + m_pSynthesizer->setPortamentoGlissando (ucValue, i); + } + + ShowNewValue ("Porta Gliss", ucValue, to_on_off); + UpdatePortamentoColor (); +} + + +void CKeyLab2DawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ +} + +void CKeyLab2DawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + int ucValue; + + switch (ucType) + { + case MIDI_CONTROL_CHANGE: + switch (ucP1) + { + case MIDI_CC_VOLUME: + char line1[LINELEN]; + snprintf(line1, LINELEN, "Volume Ch %d", ucChannel + 1); + ShowNewValue (line1, ucP2, to_percent); + break; + case MIDI_CC_PORTAMENTO: + UpdatePortamentoColor (); + ShowNewValue (m_PortamentoButton.name, ucP2, to_on_off); + break; + case MIDI_CC_SOSTENUTO: + SetButtonLight (m_SostenutoButton, ucP2); + ShowNewValue (m_SostenutoButton.name, ucP2, to_on_off); + break; + case MIDI_CC_HOLD2: + SetButtonLight (m_Hold2Button, ucP2); + ShowNewValue (m_Hold2Button.name, ucP2, to_on_off); + break; + case MIDI_CC_SUSTAIN: + SetButtonLight (m_SustainButton, ucP2); + ShowNewValue (m_SustainButton.name, ucP2, to_on_off); + break; + } + break; + + case MIDI_DAW_CHANGE: + HandleMenuEvents (m_pUI, ucP1); + + switch (ucP1) + { + case MIDI_DAW_TOGGLE_MONO: + ToggleMonoMode (ucChannel); + break; + case MIDI_DAW_TOGGLE_PORTA_GLISS: + TogglePortamentoGlisssando (ucChannel); + break; + case MIDI_DAW_SELECT_TG: + SelectTG (ucP2); + break; + case MIDI_DAW_TOGGLE_TG: + ToggleTG (ucP2); + break; + case MIDI_DAW_MASTER_VOLUME: + SetMasterVolume (ucP2); + break; + case MIDI_DAW_ENC_0: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterCutoff); + ShowNewValue ("Cutoff", ucValue, to_string); + break; + case MIDI_DAW_ENC_1: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterResonance); + ShowNewValue ("Resonance", ucValue, to_string); + break; + case MIDI_DAW_ENC_2: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterPortamentoTime); + ShowNewValue ("Portamento time", ucValue, to_string); + break; + case MIDI_DAW_ENC_5: + ucValue = SetParameter(ucChannel, ucP2, CMiniDexed::ParameterMixerDryLevel); + ShowNewValue ("Dry Level", ucValue, to_string); + break; + case MIDI_DAW_ENC_6: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterFX1Send); + ShowNewValue ("FX1Send", ucValue, to_string); + break; + case MIDI_DAW_ENC_7: + ucValue = SetTGParameter(ucChannel, ucP2, CMiniDexed::TGParameterFX2Send); + ShowNewValue ("FX2Send", ucValue, to_string); + break; + } + break; + } + + QueueUpdateDisplay (nDefaultDisplayUpdateDelay); +} + +class CKeyLabEsDawConnection : public CDAWConnection +{ +public: + CKeyLabEsDawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) override; + void UpdateState () override; + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) override; + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; +private: + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + + TMIDIRoute m_pRouteMap[18] = { + {1, 0, MIDI_NOTE_ON, 0x54, 0x7F, .ucTimerTarget=2, .usTimerExpire=m_pConfig->GetLongPressTimeout (), .bSkip=true}, // Main knob click + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_SELECT, 0, .bGroup=true}, + {1, 0, MIDI_NOTE_ON, 0x54, 0x00, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_BACK, 0, .bGroup=true}, + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_PREV, 0xFF, .bGroup=true, .bGroupHold=true}, // Main knob click + rotate + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PRESS_NEXT, 0xFF, .bGroup=true, .bGroupHold=true}, + + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::GtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_PREV, 0xFF}, // Main knob + {1, 0, MIDI_CONTROL_CHANGE, 0x3C, TMIDIRoute::LtCenter, 0, MIDI_DAW_CHANGE, MIDI_DAW_MENU_NEXT, 0xFF}, + + {1, 0, MIDI_PITCH_BEND, 0xFF, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader1 + {1, 1, MIDI_PITCH_BEND, 0xFF, 0xFF, 1, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader2 + {1, 2, MIDI_PITCH_BEND, 0xFF, 0xFF, 2, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader3 + {1, 3, MIDI_PITCH_BEND, 0xFF, 0xFF, 3, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader4 + {1, 4, MIDI_PITCH_BEND, 0xFF, 0xFF, 4, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader5 + {1, 5, MIDI_PITCH_BEND, 0xFF, 0xFF, 5, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader6 + {1, 6, MIDI_PITCH_BEND, 0xFF, 0xFF, 6, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader7 + {1, 7, MIDI_PITCH_BEND, 0xFF, 0xFF, 7, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader8 + {1, 8, MIDI_PITCH_BEND, 0xFF, 0xFF, 8, MIDI_CONTROL_CHANGE, MIDI_CC_VOLUME, 0xFF}, // Fader9 + /*{0, 0, MIDI_CONTROL_CHANGE, 96, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_FREQUENCY_CUTOFF, 0xFF}, // Knob1 + {0, 0, MIDI_CONTROL_CHANGE, 97, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_RESONANCE, 0xFF}, // Knob2 + {0, 0, MIDI_CONTROL_CHANGE, 98, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_REVERB_LEVEL, 0xFF}, // Knob3 + {0, 0, MIDI_CONTROL_CHANGE, 99, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_DETUNE_LEVEL, 0xFF}, // Knob4 + {0, 0, MIDI_CONTROL_CHANGE, 100, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob5 + {0, 0, MIDI_CONTROL_CHANGE, 101, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PORTAMENTO_TIME, 0xFF}, // Knob6 + // {0, 0, MIDI_CONTROL_CHANGE, 102, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_DETUNE_LEVEL, 0xFF}, // Knob7 + // {0, 0, MIDI_CONTROL_CHANGE, 103, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob8 + // {0, 0, MIDI_CONTROL_CHANGE, 104, 0xFF, 0, MIDI_CONTROL_CHANGE, MIDI_CC_PAN_POSITION, 0xFF}, // Knob9*/ + {1, 0xFF, 0xFF, 0xFF, 0xFF, .bSkip = true}, // skip other messages on DAW cable + {0xFF}, // Sentinel + }; +}; + +CKeyLabEsDawConnection::CKeyLabEsDawConnection (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) + :m_pSynthesizer (pSynthesizer), m_pKeyboard (pKeyboard), m_pConfig (pConfig), m_pUI (pUI) +{ + static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x51, 0x00, 0xF7}; // init DAW to Mackie mode + m_pKeyboard->SetRouteMap (m_pRouteMap); + + m_pKeyboard->Send (pInit, sizeof pInit, 0); + DisplayWrite ("MiniDexed", "", "On KeyLab Essential", 0, 0); + + UpdateState (); +} + +void CKeyLabEsDawConnection::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp) +{ + static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x00, 0x60, 0x01}; + ArturiaDisplayWrite (m_pKeyboard, pHdr, sizeof pHdr, 16, true, true, pMenu, pParam, pValue, bArrowDown, bArrowUp, true); +} + +void CKeyLabEsDawConnection::UpdateState () +{ +} + +void CKeyLabEsDawConnection::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ +} + +void CKeyLabEsDawConnection::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + //static const uint8_t pEncoder[] = {0x04, 0x01, 0x60}; + //ArturiaShowNewCCValue (pKeyboard, pEncoder, ucCh, ucCC, ucValue); + switch (ucType) + { + case MIDI_DAW_CHANGE: + HandleMenuEvents (m_pUI, ucP1); + break; + } +} + +CDAWController::CDAWController (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI) +: m_pSynthesizer (pSynthesizer), + m_pKeyboard (pKeyboard), + m_pConfig (pConfig), + m_pUI (pUI), + m_pDAWConnection (0) +{ +} + +CDAWController::~CDAWController (void) +{ + delete m_pDAWConnection; +} + +void CDAWController::OnConnect (void) +{ + static const uint8_t inquiry[] = {0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7}; + + delete m_pDAWConnection; + m_pDAWConnection = 0; + + m_pKeyboard->Send (inquiry, sizeof inquiry, 0); +} + +void CDAWController::MIDISysexHandler (u8 *pPacket, unsigned nLength, unsigned nCable) +{ + static const uint8_t pMiniLab3[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x04, 0x04}; + static const uint8_t pKeyLabEs_49[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x52}; + static const uint8_t pKeyLabEs_61[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x54}; + static const uint8_t pKeyLabEs_88[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x58}; + static const uint8_t pKeyLab2_49[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x62}; + static const uint8_t pKeyLab2_61[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x64}; + static const uint8_t pKeyLab2_88[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x68}; + static const uint8_t pKeyLabEs3_49[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x72}; + static const uint8_t pKeyLabEs3_61[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x74}; + static const uint8_t pKeyLabEs3_88[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x78}; + + if (nLength > sizeof pMiniLab3 && memcmp (pPacket, pMiniLab3, sizeof pMiniLab3) == 0) + { + m_pDAWConnection = new CMiniLab3DawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } + else if (nLength > sizeof pKeyLabEs_49 && ( + memcmp (pPacket, pKeyLabEs_49, sizeof pKeyLabEs_49) == 0 || + memcmp (pPacket, pKeyLabEs_61, sizeof pKeyLabEs_61) == 0 || + memcmp (pPacket, pKeyLabEs_88, sizeof pKeyLabEs_88) == 0)) + { + m_pDAWConnection = new CKeyLabEsDawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } + else if (nLength > sizeof pKeyLab2_61 && ( + memcmp (pPacket, pKeyLab2_49, sizeof pKeyLab2_49) == 0 || + memcmp (pPacket, pKeyLab2_61, sizeof pKeyLab2_61) == 0 || + memcmp (pPacket, pKeyLab2_88, sizeof pKeyLab2_88) == 0)) + { + m_pDAWConnection = new CKeyLab2DawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } + else if (nLength > sizeof pKeyLabEs3_49 && ( + memcmp (pPacket, pKeyLabEs3_49, sizeof pKeyLabEs3_49) == 0 || + memcmp (pPacket, pKeyLabEs3_61, sizeof pKeyLabEs3_61) == 0 || + memcmp (pPacket, pKeyLabEs3_88, sizeof pKeyLabEs3_88) == 0)) + { + m_pDAWConnection = new CKeyLabEs3DawConnection (m_pSynthesizer, m_pKeyboard, m_pConfig, m_pUI); + } +} + +void CDAWController::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + if (m_pDAWConnection) + m_pDAWConnection->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); +} + +void CDAWController::UpdateState (void) +{ + if (m_pDAWConnection) + m_pDAWConnection->UpdateState (); +} + +void CDAWController::UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + if (m_pDAWConnection) + m_pDAWConnection->UpdateMenu (Type, ucPage, ucOP, ucTG); +} + +void CDAWController::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + if (m_pDAWConnection) + m_pDAWConnection->MIDIListener (ucCable, ucChannel, ucType, ucP1, ucP2); +} diff --git a/src/dawcontroller.h b/src/dawcontroller.h new file mode 100644 index 000000000..0b1f00511 --- /dev/null +++ b/src/dawcontroller.h @@ -0,0 +1,54 @@ +// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi +// Copyright (C) 2024 The MiniDexed Team +// +// This program 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 . +// +#ifndef _dawcontroller_h +#define _dawcontroller_h + +#include +#include "uimenu.h" + +class CMIDIKeyboard; +class CMiniDexed; +class CDAWConnection; +class CConfig; +class CUserInterface; + +class CDAWController +{ +public: + CDAWController (CMiniDexed *pSynthesizer, CMIDIKeyboard *pKeyboard, CConfig *pConfig, CUserInterface *pUI); + ~CDAWController (void); + + void OnConnect (void); + void MIDISysexHandler (u8 *pPacket, unsigned nLength, unsigned nCable); + + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + + void UpdateState (void); + void UpdateMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG); + + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2); + +private: + CMiniDexed *m_pSynthesizer; + CMIDIKeyboard *m_pKeyboard; + CConfig *m_pConfig; + CUserInterface *m_pUI; + CDAWConnection *m_pDAWConnection; +}; + +#endif diff --git a/src/dexedadapter.h b/src/dexedadapter.h index 573e80ef2..c92aea833 100644 --- a/src/dexedadapter.h +++ b/src/dexedadapter.h @@ -23,7 +23,10 @@ #include #include -#include +#include + +#include "effect_3bandeqmono.h" +#include "compressor.h" #define DEXED_OP_ENABLE (DEXED_OP_OSC_DETUNE + 1) @@ -33,8 +36,11 @@ class CDexedAdapter : public Dexed { public: - CDexedAdapter (uint8_t maxnotes, int rate) - : Dexed (maxnotes, rate) + CDexedAdapter (uint8_t maxnotes, unsigned samplerate): + Dexed (maxnotes, samplerate), + EQ {(float)samplerate}, + Compr {(float)samplerate}, + m_bCompressorEnable {} { } @@ -63,6 +69,11 @@ class CDexedAdapter : public Dexed { m_SpinLock.Acquire (); Dexed::getSamples (buffer, n_samples); + EQ.process(buffer, n_samples); + if (m_bCompressorEnable) + { + Compr.doCompression (buffer, n_samples); + } m_SpinLock.Release (); } @@ -80,8 +91,29 @@ class CDexedAdapter : public Dexed m_SpinLock.Release (); } + void setCompressorEnable(bool enable) + { + m_SpinLock.Acquire (); + m_bCompressorEnable = enable; + m_SpinLock.Release (); + } + + void resetState () + { + m_SpinLock.Acquire (); + deactivate (); + resetFxState (); + EQ.resetState (); + Compr.resetStates (); + m_SpinLock.Release (); + } + + AudioEffect3BandEQMono EQ; + Compressor Compr; + private: CSpinLock m_SpinLock; + bool m_bCompressorEnable; }; #endif diff --git a/src/effect.cpp b/src/effect.cpp new file mode 100644 index 000000000..01ef96f91 --- /dev/null +++ b/src/effect.cpp @@ -0,0 +1,236 @@ +#include + +#include "effect.h" +#include "midi.h" +#include "effect_cloudseed2.h" +#include "effect_compressor.h" + +static std::string ToOnOff (int nValue, int nWidth) +{ + static const char *OnOff[] = {"Off", "On"}; + + assert ((unsigned) nValue < sizeof OnOff / sizeof OnOff[0]); + + return OnOff[nValue]; +} + +static std::string ToDelayMode (int nValue, int nWidth) +{ + static const char *Mode[] = {"Dual", "Crossover", "PingPong"}; + + assert ((unsigned) nValue < sizeof Mode / sizeof Mode[0]); + + return Mode[nValue]; +} + +static std::string ToDelayTime (int nValue, int nWidth) +{ + static const char *Sync[] = {"1/1", "1/1T", "1/2", "1/2T", "1/4", "1/4T", "1/8", "1/8T", "1/16", "1/16T", "1/32", "1/32T"}; + + assert (nValue >= 0 && nValue <= 112); + + if (nValue <= 100) + return std::to_string(nValue * 10) + " ms"; + + return Sync[nValue - 100 - 1]; +} + +static std::string ToBPM(int nValue, int nWidth) +{ + return std::to_string(nValue) + " BPM"; +} + +static std::string ToHz (int nValue, int nWidth) +{ + uint16_t hz = MIDI_EQ_HZ[nValue]; + char buf[20] = {}; + + if (hz < 1000) + return std::to_string (hz) + " Hz"; + + std::snprintf (buf, sizeof(buf), "%.1f kHz", hz/1000.0); + return buf; +} + +static std::string ToDryWet (int nValue, int nWidth) +{ + unsigned dry, wet; + if (nValue <= 50) + { + dry = 100; + wet = nValue * 2; + } + else + { + dry = 100 - ((nValue - 50) * 2); + wet = 100; + } + + return std::to_string (dry) + ":" + std::to_string(wet) + (wet == 0 ? " Off" : ""); +} + +static std::string ToEffectName (int nValue, int nWidth) +{ + assert (nValue >= 0 && nValue < FX::effects_num); + return FX::s_effects[nValue].Name; +} + +static std::string TodB (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dB"; +} + +static std::string TodBFS (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dBFS"; +} + +static std::string ToMillisec (int nValue, int nWidth) +{ + return std::to_string (nValue) + " ms"; +} + +static std::string ToRatio (int nValue, int nWidth) +{ + if (nValue == AudioEffectCompressor::CompressorRatioInf) + return "INF:1"; + + return std::to_string (nValue) + ":1"; +} + +FX::FXParameterType FX::s_FXParameter[FX::FXParameterUnknown] = +{ + {0, FX::effects_num - 1, 0, 1, "Slot1", ToEffectName, FX::FXSaveAsString}, + {0, FX::effects_num - 1, 0, 1, "Slot2", ToEffectName, FX::FXSaveAsString}, + {0, FX::effects_num - 1, 0, 1, "Slot3", ToEffectName, FX::FXSaveAsString}, + {0, 100, 0, 1, "YKChorusMix", ToDryWet}, + {0, 1, 1, 1, "YKChorusEnable1", ToOnOff}, + {0, 1, 1, 1, "YKChorusEnable2", ToOnOff}, + {0, 100, 50, 1, "YKChorusLFORate1"}, + {0, 100, 83, 1, "YKChorusLFORate2"}, + {0, 1, 0, 1, "YKChorusBypass", ToOnOff}, + {0, 100, 0, 1, "DreamDelayMix", ToDryWet}, + {0, 2, 0, 1, "DreamDelayMode", ToDelayMode}, + {0, 112, 36, 1, "DreamDelayTime", ToDelayTime, FX::FXComposite}, + {0, 112, 36, 1, "DreamDelayTimeL", ToDelayTime}, + {0, 112, 36, 1, "DreamDelayTimeR", ToDelayTime}, + {30, 240, 120, 1, "DreamDelayTempo", ToBPM}, + {0, 100, 60, 1, "DreamDelayFeedback"}, + {0, 60, 50, 1, "DreamDelayHighCut", ToHz}, + {0, 1, 0, 1, "DreamDelayBypass", ToOnOff}, + {0, 100, 0, 1, "PlateReverbMix", ToDryWet}, + {0, 99, 50, 1, "PlateReverbSize"}, + {0, 99, 25, 1, "PlateReverbHighDamp"}, + {0, 99, 25, 1, "PlateReverbLowDamp"}, + {0, 99, 85, 1, "PlateReverbLowPass"}, + {0, 99, 65, 1, "PlateReverbDiffusion"}, + {0, 1, 0, 1, "PlateReverbBypass", ToOnOff}, + {0, AudioEffectCloudSeed2::presets_num - 1, 0, 1, "CloudSeed2Preset", AudioEffectCloudSeed2::getPresetName, FX::FXComposite | FX::FXSaveAsString}, + {0, 1, 0, 1, "CloudSeed2Interpolation", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2LowCutEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2HighCutEnabled", ToOnOff}, + {0, 127, 0, 1, "CloudSeed2InputMix"}, + {0, 127, 0, 1, "CloudSeed2LowCut"}, + {0, 127, 127, 1, "CloudSeed2HighCut"}, + {0, 127, 127, 1, "CloudSeed2DryOut"}, + {0, 127, 0, 1, "CloudSeed2EarlyOut"}, + {0, 127, 0, 1, "CloudSeed2LateOut"}, + {0, 1, 0, 1, "CloudSeed2TapEnabled", ToOnOff}, + {0, 127, 64, 1, "CloudSeed2TapCount"}, + {0, 127, 127, 1, "CloudSeed2TapDecay"}, + {0, 127, 0, 1, "CloudSeed2TapPredelay"}, + {0, 127, 62, 1, "CloudSeed2TapLength"}, + {0, 1, 0, 1, "CloudSeed2EarlyDiffuseEnabled", ToOnOff}, + {1, 12, 4, 1, "CloudSeed2EarlyDiffuseCount"}, + {0, 127, 18, 1, "CloudSeed2EarlyDiffuseDelay"}, + {0, 127, 19, 1, "CloudSeed2EarlyDiffuseModAmount"}, + {0, 127, 89, 1, "CloudSeed2EarlyDiffuseFeedback"}, + {0, 127, 20, 1, "CloudSeed2EarlyDiffuseModRate"}, + {0, 1, 1, 1, "CloudSeed2LateMode", AudioEffectCloudSeed2::GetLateMode}, + {1, 12, 6, 1, "CloudSeed2LateLineCount"}, + {0, 1, 0, 1, "CloudSeed2LateDiffuseEnabled", ToOnOff}, + {1, 8, 2, 1, "CloudSeed2LateDiffuseCount"}, + {0, 127, 64, 1, "CloudSeed2LateLineSize"}, + {0, 127, 19, 1, "CloudSeed2LateLineModAmount"}, + {0, 127, 64, 1, "CloudSeed2LateDiffuseDelay"}, + {0, 127, 20, 1, "CloudSeed2LateDiffuseModAmount"}, + {0, 127, 62, 1, "CloudSeed2LateLineDecay"}, + {0, 127, 20, 1, "CloudSeed2LateLineModRate"}, + {0, 127, 90, 1, "CloudSeed2LateDiffuseFeedback"}, + {0, 127, 19, 1, "CloudSeed2LateDiffuseModRate"}, + {0, 1, 0, 1, "CloudSeed2EqLowShelfEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2EqHighShelfEnabled", ToOnOff}, + {0, 1, 0, 1, "CloudSeed2EqLowpassEnabled", ToOnOff}, + {0, 127, 40, 1, "CloudSeed2EqLowFreq"}, + {0, 127, 65, 1, "CloudSeed2EqHighFreq"}, + {0, 127, 104, 1, "CloudSeed2EqCutoff"}, + {0, 127, 107, 1, "CloudSeed2EqLowGain"}, + {0, 127, 108, 1, "CloudSeed2EqHighGain"}, + {0, 127, 0, 1, "CloudSeed2EqCrossSeed"}, + {0, 127, 62, 1, "CloudSeed2SeedTap"}, + {0, 127, 6, 1, "CloudSeed2SeedDiffusion"}, + {0, 127, 12, 1, "CloudSeed2SeedDelay"}, + {0, 127, 19, 1, "CloudSeed2SeedPostDiffusion"}, + {0, 1, 0, 1, "CloudSeed2Bypass", ToOnOff}, + {-20, 20, 0, 1, "CompressorPreGain", TodB}, + {-60, 0, -20, 1, "CompressorThresh", TodBFS}, + {1, AudioEffectCompressor::CompressorRatioInf, 5, 1, "CompressorRatio", ToRatio}, + {0, 1000, 5, 5, "CompressorAttack", ToMillisec}, + {0, 2000, 200, 5, "CompressorRelease", ToMillisec}, + {-20, 20, 0, 1, "CompressorMakeupGain", TodB}, + {0, 1, 0, 1, "CompressorHPFilterEnable", ToOnOff}, + {0, 1, 0, 1, "CompressorBypass", ToOnOff}, + {-24, 24, 0, 1, "EQLow", TodB}, + {-24, 24, 0, 1, "EQMid", TodB}, + {-24, 24, 0, 1, "EQHigh", TodB}, + {-24, 24, 0, 1, "EQGain", TodB}, + {0, 46, 24, 1, "EQLowMidFreq", ToHz}, + {28, 59, 44, 1, "EQMidHighFreq", ToHz}, + {0, 1, 0, 1, "EQBypass", ToOnOff}, + {0, 99, 0, 1, "ReturnLevel"}, + {0, 1, 0, 1, "Bypass", ToOnOff}, +}; + +constexpr const FX::EffectType FX::s_effects[]; + +uint8_t getIDFromEffectName(const char* name) +{ + for(uint8_t i = 0; i < FX::effects_num; ++i) + if (strcmp(FX::s_effects[i].Name, name) == 0) + return i; + + return 0; +} + +int FX::getIDFromName(TFXParameter param, const char* name) +{ + switch (param) + { + case FX::FXParameterSlot0: + case FX::FXParameterSlot1: + case FX::FXParameterSlot2: + return getIDFromEffectName(name); + case FX::FXParameterCloudSeed2Preset: + return AudioEffectCloudSeed2::getIDFromPresetName(name); + default: + assert(false); + } + return 0; +} + +const char *FX::getNameFromID(TFXParameter param, int nID) +{ + switch (param) + { + case FX::FXParameterSlot0: + case FX::FXParameterSlot1: + case FX::FXParameterSlot2: + assert (nID < FX::effects_num); + return FX::s_effects[nID].Name; + case FX::FXParameterCloudSeed2Preset: + return AudioEffectCloudSeed2::getPresetNameChar(nID); + default: + assert(false); + } + return 0; +} diff --git a/src/effect.h b/src/effect.h new file mode 100644 index 000000000..362b6513d --- /dev/null +++ b/src/effect.h @@ -0,0 +1,142 @@ +#pragma once + +#include +#include + +class FX +{ +public: + static constexpr int FXComposite = 1 << 0; // updates multiple controls, it shouldn't update the controls at startup and performance load + static constexpr int FXSaveAsString = 1 << 1; // save this parameter as string in the performace file + + enum TFXParameter + { + FXParameterSlot0, + FXParameterSlot1, + FXParameterSlot2, + FXParameterYKChorusMix, + FXParameterYKChorusEnable1, + FXParameterYKChorusEnable2, + FXParameterYKChorusLFORate1, + FXParameterYKChorusLFORate2, + FXParameterYKChorusBypass, + FXParameterDreamDelayMix, + FXParameterDreamDelayMode, + FXParameterDreamDelayTime, + FXParameterDreamDelayTimeL, + FXParameterDreamDelayTimeR, + FXParameterDreamDelayTempo, + FXParameterDreamDelayFeedback, + FXParameterDreamDelayHighCut, + FXParameterDreamDelayBypass, + FXParameterPlateReverbMix, + FXParameterPlateReverbSize, + FXParameterPlateReverbHighDamp, + FXParameterPlateReverbLowDamp, + FXParameterPlateReverbLowPass, + FXParameterPlateReverbDiffusion, + FXParameterPlateReverbBypass, + FXParameterCloudSeed2Preset, + FXParameterCloudSeed2Interpolation, + FXParameterCloudSeed2LowCutEnabled, + FXParameterCloudSeed2HighCutEnabled, + FXParameterCloudSeed2InputMix, + FXParameterCloudSeed2LowCut, + FXParameterCloudSeed2HighCut, + FXParameterCloudSeed2DryOut, + FXParameterCloudSeed2EarlyOut, + FXParameterCloudSeed2LateOut, + FXParameterCloudSeed2TapEnabled, + FXParameterCloudSeed2TapCount, + FXParameterCloudSeed2TapDecay, + FXParameterCloudSeed2TapPredelay, + FXParameterCloudSeed2TapLength, + FXParameterCloudSeed2EarlyDiffuseEnabled, + FXParameterCloudSeed2EarlyDiffuseCount, + FXParameterCloudSeed2EarlyDiffuseDelay, + FXParameterCloudSeed2EarlyDiffuseModAmount, + FXParameterCloudSeed2EarlyDiffuseFeedback, + FXParameterCloudSeed2EarlyDiffuseModRate, + FXParameterCloudSeed2LateMode, + FXParameterCloudSeed2LateLineCount, + FXParameterCloudSeed2LateDiffuseEnabled, + FXParameterCloudSeed2LateDiffuseCount, + FXParameterCloudSeed2LateLineSize, + FXParameterCloudSeed2LateLineModAmount, + FXParameterCloudSeed2LateDiffuseDelay, + FXParameterCloudSeed2LateDiffuseModAmount, + FXParameterCloudSeed2LateLineDecay, + FXParameterCloudSeed2LateLineModRate, + FXParameterCloudSeed2LateDiffuseFeedback, + FXParameterCloudSeed2LateDiffuseModRate, + FXParameterCloudSeed2EqLowShelfEnabled, + FXParameterCloudSeed2EqHighShelfEnabled, + FXParameterCloudSeed2EqLowpassEnabled, + FXParameterCloudSeed2EqLowFreq, + FXParameterCloudSeed2EqHighFreq, + FXParameterCloudSeed2EqCutoff, + FXParameterCloudSeed2EqLowGain, + FXParameterCloudSeed2EqHighGain, + FXParameterCloudSeed2EqCrossSeed, + FXParameterCloudSeed2SeedTap, + FXParameterCloudSeed2SeedDiffusion, + FXParameterCloudSeed2SeedDelay, + FXParameterCloudSeed2SeedPostDiffusion, + FXParameterCloudSeed2Bypass, + FXParameterCompressorPreGain, + FXParameterCompressorThresh, + FXParameterCompressorRatio, + FXParameterCompressorAttack, + FXParameterCompressorRelease, + FXParameterCompressorMakeupGain, + FXParameterCompressorHPFilterEnable, + FXParameterCompressorBypass, + FXParameterEQLow, + FXParameterEQMid, + FXParameterEQHigh, + FXParameterEQGain, + FXParameterEQLowMidFreq, + FXParameterEQMidHighFreq, + FXParameterEQBypass, + FXParameterReturnLevel, + FXParameterBypass, + FXParameterUnknown, + }; + + typedef std::string TToString (int nValue, int nWidth); + + struct FXParameterType + { + int Minimum; + int Maximum; + int Default; + int Increment; + const char *Name; + TToString *ToString; + int Flags; + }; + + static FX::FXParameterType s_FXParameter[]; + + struct EffectType + { + const char *Name; + const unsigned MinID; + const unsigned MaxID; + }; + + static constexpr const EffectType s_effects[] = { + {"None"}, + {"YKChorus", FXParameterYKChorusMix, FXParameterYKChorusBypass}, + {"DreamDelay", FXParameterDreamDelayMix, FXParameterDreamDelayBypass}, + {"PlateReverb", FXParameterPlateReverbMix, FXParameterPlateReverbBypass}, + {"CloudSeed2", FXParameterCloudSeed2Preset, FXParameterCloudSeed2Bypass}, + {"Compressor", FXParameterCompressorPreGain, FXParameterCompressorBypass}, + {"EQ", FXParameterEQLow, FXParameterEQBypass}, + }; + static constexpr uint8_t effects_num = sizeof s_effects / sizeof *s_effects; + static constexpr uint8_t slots_num = 3; + + static const char *getNameFromID(TFXParameter param, int nID); + static int getIDFromName(TFXParameter param, const char* name); +}; diff --git a/src/effect_3bandeq.h b/src/effect_3bandeq.h new file mode 100644 index 000000000..db63375b7 --- /dev/null +++ b/src/effect_3bandeq.h @@ -0,0 +1,95 @@ +/* + * DISTHRO 3 Band EQ + * Ported from https://github.com/DISTRHO/Mini-Series/blob/master/plugins/3BandEQ + * Ported from https://github.com/jnonis/MiniDexed + */ + +#pragma once + +#include + +#include "effect_3bandeqmono.h" + +class AudioEffect3BandEQ +{ +public: + AudioEffect3BandEQ(float samplerate): + bypass{}, + eqL{samplerate}, + eqR{samplerate} + { + } + + void setLow_dB(float value) + { + eqL.setLow_dB(value); + eqR.setLow_dB(value); + } + + void setMid_dB(float value) + { + eqL.setMid_dB(value); + eqR.setMid_dB(value); + } + + void setHigh_dB(float value) + { + eqL.setHigh_dB(value); + eqR.setHigh_dB(value); + } + + void setGain_dB(float value) + { + eqL.setGain_dB(value); + eqR.setGain_dB(value); + } + + float setLowMidFreq(float value) + { + eqL.setLowMidFreq(value); + return eqR.setLowMidFreq(value); + } + + float setMidHighFreq(float value) + { + eqL.setMidHighFreq(value); + return eqR.setMidHighFreq(value); + } + + unsigned setLowMidFreq_n(unsigned value) + { + eqL.setLowMidFreq_n(value); + return eqR.setLowMidFreq_n(value); + } + + unsigned setMidHighFreq_n(unsigned value) + { + eqL.setMidHighFreq_n(value); + return eqR.setMidHighFreq_n(value); + } + + float getLow_dB() const { return eqR.getLow_dB(); } + float getMid_dB() const { return eqR.getMid_dB(); } + float getHigh_dB() const { return eqR.getHigh_dB(); } + float getGain_dB() const { return eqR.getGain_dB(); } + float getLowMidFreq() const { return eqR.getLowMidFreq(); } + float getMidHighFreq() const { return eqR.getMidHighFreq(); } + unsigned getLowMidFreq_n() const { return eqR.getLowMidFreq_n(); } + unsigned getMidHighFreq_n() const { return eqR.getMidHighFreq_n(); } + + void resetState() { eqL.resetState(); eqR.resetState(); } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len) + { + if (bypass) return; + + eqL.process(blockL, len); + eqR.process(blockR, len); + } + + std::atomic bypass; + +private: + AudioEffect3BandEQMono eqL; + AudioEffect3BandEQMono eqR; +}; diff --git a/src/effect_3bandeqmono.h b/src/effect_3bandeqmono.h new file mode 100644 index 000000000..f198a3f66 --- /dev/null +++ b/src/effect_3bandeqmono.h @@ -0,0 +1,130 @@ +/* + * DISTHRO 3 Band EQ + * Ported from https://github.com/DISTRHO/Mini-Series/blob/master/plugins/3BandEQ + * Ported from https://github.com/jnonis/MiniDexed + */ + +#pragma once + +#include + +#include "midi.h" + +class AudioEffect3BandEQMono +{ +public: + AudioEffect3BandEQMono(float samplerate): + samplerate{samplerate}, + fLow{}, fMid{}, fHigh{}, fGain{}, fLowMidFreq{}, fMidHighFreq{}, + nLowMidFreq{24}, /* 315Hz */ + nMidHighFreq{44}, /* 3.2kHz */ + tmpLP{}, tmpHP{} + { + setLow_dB(fLow); + setMid_dB(fMid); + setHigh_dB(fHigh); + setGain_dB(fGain); + setLowMidFreq_n(nLowMidFreq); + setMidHighFreq_n(nMidHighFreq); + } + + void setLow_dB(float value) + { + fLow = value; + lowVol = std::pow(10.0f, fLow / 20.0f); + } + + void setMid_dB(float value) + { + fMid = value; + midVol = std::pow(10.0f, fMid / 20.0f); + } + + void setHigh_dB(float value) + { + fHigh = value; + highVol = std::pow(10.0f, fHigh / 20.0f); + } + + void setGain_dB(float value) + { + fGain = value; + outVol = std::pow(10.0f, fGain / 20.0f); + } + + float setLowMidFreq(float value) + { + fLowMidFreq = std::min(value, fMidHighFreq); + xLP = std::exp(-2.0f * M_PI * fLowMidFreq / samplerate); + a0LP = 1.0f - xLP; + b1LP = -xLP; + return fLowMidFreq; + } + + float setMidHighFreq(float value) + { + fMidHighFreq = std::max(value, fLowMidFreq); + xHP = std::exp(-2.0f * M_PI * fMidHighFreq / samplerate); + a0HP = 1.0f - xHP; + b1HP = -xHP; + return fMidHighFreq; + } + + unsigned setLowMidFreq_n(unsigned value) + { + nLowMidFreq = std::min(value, nMidHighFreq); + setLowMidFreq(MIDI_EQ_HZ[nLowMidFreq]); + return nLowMidFreq; + } + + unsigned setMidHighFreq_n(unsigned value) + { + nMidHighFreq = std::max(value, nLowMidFreq); + setMidHighFreq(MIDI_EQ_HZ[nMidHighFreq]); + return nMidHighFreq; + } + + float getLow_dB() const { return fLow; } + float getMid_dB() const { return fMid; } + float getHigh_dB() const { return fHigh; } + float getGain_dB() const { return fGain; } + float getLowMidFreq() const { return fLowMidFreq; } + float getMidHighFreq() const { return fMidHighFreq; } + unsigned getLowMidFreq_n() const { return nLowMidFreq; } + unsigned getMidHighFreq_n() const { return nMidHighFreq; } + + void resetState() { tmpLP = 0.0f; tmpHP = 0.0f; } + + void process(float32_t* block, uint16_t len) + { + float outLP, outHP; + + if (!fLow && !fMid && !fHigh && !fGain) return; + + for (uint16_t i=0; i < len; ++i) + { + float inValue = std::isnan(block[i]) ? 0.0f : block[i]; + + tmpLP = a0LP * inValue - b1LP * tmpLP; + outLP = tmpLP; + + tmpHP = a0HP * inValue - b1HP * tmpHP; + outHP = inValue - tmpHP; + + block[i] = (outLP*lowVol + (inValue - outLP - outHP)*midVol + outHP*highVol) * outVol; + } + } + +private: + float samplerate; + + float fLow, fMid, fHigh, fGain, fLowMidFreq, fMidHighFreq; + unsigned nLowMidFreq, nMidHighFreq; + + float lowVol, midVol, highVol, outVol; + + float xLP, a0LP, b1LP; + float xHP, a0HP, b1HP; + + float tmpLP, tmpHP; +}; diff --git a/src/effect_chain.h b/src/effect_chain.h new file mode 100644 index 000000000..90bd576fe --- /dev/null +++ b/src/effect_chain.h @@ -0,0 +1,89 @@ +#pragma once + +#include + +#include "effect_3bandeq.h" +#include "effect_compressor.h" +#include "effect_cloudseed2.h" +#include "effect_dreamdelay.h" +#include "effect_platervbstereo.h" +#include "effect_ykchorus.h" + +class AudioFXChain +{ +public: + typedef std::function process_t; + + AudioFXChain(float samplerate): + yk_chorus{samplerate}, + dream_delay{samplerate}, + plate_reverb{samplerate}, + cloudseed2{samplerate}, + compressor{samplerate}, + eq{samplerate}, + bypass{}, + funcs{ + [this](float *inputL, float *inputR, uint16_t len) {}, + [this](float *inputL, float *inputR, uint16_t len) { yk_chorus.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { dream_delay.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { plate_reverb.process(inputL, inputR, inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { cloudseed2.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { compressor.process(inputL, inputR, len); }, + [this](float *inputL, float *inputR, uint16_t len) { eq.process(inputL, inputR, len); }, + }, + level{} + { + } + + float get_level() { return level; } + void set_level(float value) { level = constrain(value, 0.0f, 1.0f); } + + void process (float *inputL, float *inputR, uint16_t len) + { + if (bypass) return; + + for (int i = 0; i < FX::slots_num; ++i) + if (uint8_t id = slots[i]) + funcs[id](inputL, inputR, len); + + if (level != 1.0f) + { + arm_scale_f32(inputL, level, inputL, len); + arm_scale_f32(inputR, level, inputR, len); + } + } + + void resetState() + { + dream_delay.resetState(); + plate_reverb.reset(); + compressor.resetState(); + eq.resetState(); + + cloudseed2.setRampedDown(); + cloudseed2.setNeedBufferClear(); + } + + void setSlot(uint8_t slot, uint8_t effect_id) + { + assert(slot < FX::slots_num); + assert(effect_id < FX::effects_num); + + slots[slot] = effect_id; + } + + AudioEffectYKChorus yk_chorus; + AudioEffectDreamDelay dream_delay; + AudioEffectPlateReverb plate_reverb; + AudioEffectCloudSeed2 cloudseed2; + AudioEffectCompressor compressor; + AudioEffect3BandEQ eq; + + std::atomic bypass; + +private: + std::atomic slots[FX::slots_num]; + const process_t funcs[FX::effects_num]; + + float level; +}; diff --git a/src/effect_cloudseed2.cpp b/src/effect_cloudseed2.cpp new file mode 100644 index 000000000..357468c54 --- /dev/null +++ b/src/effect_cloudseed2.cpp @@ -0,0 +1,792 @@ +#include "effect_cloudseed2.h" + +namespace Parameter = Cloudseed::Parameter; + +static const float UInit[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.0, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.5, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.4957000017166138, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.146699994802475, + [Parameter::EarlyDiffuseModAmount] = 0.1559000015258789, + [Parameter::EarlyDiffuseFeedback] = 0.7066999673843384, + [Parameter::EarlyDiffuseModRate] = 0.1626999974250793, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.4599999785423279, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.2226999998092651, + [Parameter::LateLineSize] = 0.5, + [Parameter::LateLineModAmount] = 0.1560000032186508, + [Parameter::LateDiffuseDelay] = 0.510699987411499, + [Parameter::LateDiffuseModAmount] = 0.1600999981164932, + [Parameter::LateLineDecay] = 0.4959999918937683, + [Parameter::LateLineModRate] = 0.1652999967336655, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1507000029087067, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3199999928474426, + [Parameter::EqHighFreq] = 0.5151999592781067, + [Parameter::EqCutoff] = 0.8260999917984009, + [Parameter::EqLowGain] = 0.8495000004768372, + [Parameter::EqHighGain] = 0.8504999876022339, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.01009999960660934, + [Parameter::SeedDiffusion] = 0.05059999972581863, + [Parameter::SeedDelay] = 0.1002999991178513, + [Parameter::SeedPostDiffusion] = 0.1500999927520752, +}; + +static const float FXDivineInspiration[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 0.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7172999978065491, + [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, + [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4786999821662903, + [Parameter::LateLineSize] = 0.687999963760376, + [Parameter::LateLineModAmount] = 0.7547000050544739, + [Parameter::LateDiffuseDelay] = 0.6279999613761902, + [Parameter::LateDiffuseModAmount] = 0.4614000022411346, + [Parameter::LateLineDecay] = 0.8199999928474426, + [Parameter::LateLineModRate] = 0.6279999613761902, + [Parameter::LateDiffuseFeedback] = 0.6319999694824219, + [Parameter::LateDiffuseModRate] = 0.3267000019550323, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1469999998807907, + [Parameter::SeedDelay] = 0.2309999912977219, + [Parameter::SeedPostDiffusion] = 0.2899999916553497, +}; + +static const float FXLawsOfPhysics[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.1772999912500381, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.7999999523162842, + [Parameter::LateOut] = 0.6439999938011169, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 1.0, + [Parameter::TapDecay] = 0.5040000081062317, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 1.0, + [Parameter::EarlyDiffuseDelay] = 0.7706999778747559, + [Parameter::EarlyDiffuseModAmount] = 0.6158999800682068, + [Parameter::EarlyDiffuseFeedback] = 0.5026999711990356, + [Parameter::EarlyDiffuseModRate] = 0.3666999936103821, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6039999723434448, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.3240000009536743, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.5759999752044678, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.2680000066757202, + [Parameter::SeedTap] = 0.3489999771118164, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float FXSlowBraaam[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.1319999992847443, + [Parameter::LowCut] = 0.3599999845027924, + [Parameter::HighCut] = 0.1400000005960464, + [Parameter::DryOut] = 0.0, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.6839999556541443, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.5839999914169312, + [Parameter::TapDecay] = 0.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7759999632835388, + [Parameter::EarlyDiffuseDelay] = 0.4986999928951263, + [Parameter::EarlyDiffuseModAmount] = 0.4838999807834625, + [Parameter::EarlyDiffuseFeedback] = 0.5467000007629395, + [Parameter::EarlyDiffuseModRate] = 0.3026999831199646, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.08399999886751175, + [Parameter::LateLineModAmount] = 0.1519999951124191, + [Parameter::LateDiffuseDelay] = 0.363999992609024, + [Parameter::LateDiffuseModAmount] = 0.4387999773025513, + [Parameter::LateLineDecay] = 0.5640000104904175, + [Parameter::LateLineModRate] = 0.2532999813556671, + [Parameter::LateDiffuseFeedback] = 0.7106999754905701, + [Parameter::LateDiffuseModRate] = 0.1826999932527542, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1119999960064888, + [Parameter::EqHighFreq] = 0.5813999772071838, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.8240000009536743, + [Parameter::EqHighGain] = 0.8479999899864197, + [Parameter::EqCrossSeed] = 0.1759999990463257, + [Parameter::SeedTap] = 0.7879999876022339, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.1730999946594238, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float FXTheUpsideDown[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.1772999912500381, + [Parameter::HighCut] = 0.3759999871253967, + [Parameter::DryOut] = 0.7080000042915344, + [Parameter::EarlyOut] = 0.9559999704360962, + [Parameter::LateOut] = 0.6279999613761902, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.1599999964237213, + [Parameter::TapDecay] = 0.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 1.0, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 1.0, + [Parameter::EarlyDiffuseDelay] = 0.9466999769210815, + [Parameter::EarlyDiffuseModAmount] = 0.5598999857902527, + [Parameter::EarlyDiffuseFeedback] = 0.510699987411499, + [Parameter::EarlyDiffuseModRate] = 0.4587000012397766, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6039999723434448, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.3919999897480011, + [Parameter::LateLineModAmount] = 0.3319999873638153, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.715999960899353, + [Parameter::LateLineModRate] = 0.1412999927997589, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.1319999992847443, + [Parameter::SeedTap] = 0.8539999723434448, + [Parameter::SeedDiffusion] = 0.1129999980330467, + [Parameter::SeedDelay] = 0.3800999820232391, + [Parameter::SeedPostDiffusion] = 0.2633000016212463, +}; + +static const float LBigSoundStage[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.687999963760376, + [Parameter::LateOut] = 0.7559999823570251, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.4172999858856201, + [Parameter::EarlyDiffuseDelay] = 0.6947000026702881, + [Parameter::EarlyDiffuseModAmount] = 0.3425999879837036, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.3506999909877777, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.6240000128746033, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 1.0, + [Parameter::LateLineSize] = 0.2479999959468842, + [Parameter::LateLineModAmount] = 0.0, + [Parameter::LateDiffuseDelay] = 0.1759999990463257, + [Parameter::LateDiffuseModAmount] = 0.1959999948740005, + [Parameter::LateLineDecay] = 0.4120000004768372, + [Parameter::LateLineModRate] = 0.0, + [Parameter::LateDiffuseFeedback] = 0.8840000033378601, + [Parameter::LateDiffuseModRate] = 0.2586999833583832, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.2639999985694885, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.9720000028610229, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1469999998807907, + [Parameter::SeedDelay] = 0.2309999912977219, + [Parameter::SeedPostDiffusion] = 0.2899999916553497, +}; + +static const float LDiffusionCyclone[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0746999979019165, + [Parameter::LowCut] = 0.1292999982833862, + [Parameter::HighCut] = 0.6119999885559082, + [Parameter::DryOut] = 0.9079999923706055, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2132999897003174, + [Parameter::EarlyDiffuseDelay] = 0.2906999886035919, + [Parameter::EarlyDiffuseModAmount] = 0.1145999953150749, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2226999998092651, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4786999821662903, + [Parameter::LateLineSize] = 0.3199999928474426, + [Parameter::LateLineModAmount] = 0.2586999833583832, + [Parameter::LateDiffuseDelay] = 0.3759999871253967, + [Parameter::LateDiffuseModAmount] = 0.2893999814987183, + [Parameter::LateLineDecay] = 0.7519999742507935, + [Parameter::LateLineModRate] = 0.2239999920129776, + [Parameter::LateDiffuseFeedback] = 0.7080000042915344, + [Parameter::LateDiffuseModRate] = 0.2506999969482422, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.8172999620437622, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.0, + [Parameter::SeedDiffusion] = 0.1219999939203262, + [Parameter::SeedDelay] = 0.3039999902248383, + [Parameter::SeedPostDiffusion] = 0.3409999907016754, +}; + +static const float LScreamIntoTheVoid[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.4852999746799469, + [Parameter::DryOut] = 0.6998999714851379, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.7786999940872192, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.1599999964237213, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.7172999978065491, + [Parameter::EarlyDiffuseDelay] = 0.7386999726295471, + [Parameter::EarlyDiffuseModAmount] = 0.2505999803543091, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.3999999761581421, + [Parameter::LateLineModAmount] = 0.146699994802475, + [Parameter::LateDiffuseDelay] = 0.3519999980926514, + [Parameter::LateDiffuseModAmount] = 0.3653999865055084, + [Parameter::LateLineDecay] = 0.7199999690055847, + [Parameter::LateLineModRate] = 0.1959999948740005, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5346999764442444, + [Parameter::EqCutoff] = 0.5012999773025513, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.543999969959259, + [Parameter::EqCrossSeed] = 0.1119999960064888, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.07299999892711639, + [Parameter::SeedDelay] = 0.1939999908208847, + [Parameter::SeedPostDiffusion] = 0.3039999902248383, +}; + +static const float M90sDigitalReverb[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 0.4959999918937683, + [Parameter::LateOut] = 0.6173999905586243, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, + [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, + [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.2680000066757202, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.3120000064373016, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MAiryAmbience[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.07069999724626541, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 0.9785999655723572, + [Parameter::EarlyOut] = 0.5559999942779541, + [Parameter::LateOut] = 0.4280999898910522, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2360000014305115, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.1079999953508377, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.2506999969482422, + [Parameter::LateDiffuseModAmount] = 0.2480999976396561, + [Parameter::LateLineDecay] = 0.5879999995231628, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1959999948740005, + [Parameter::EqHighFreq] = 0.7013999819755554, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.687999963760376, + [Parameter::EqHighGain] = 0.2746999859809875, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MDarkPlate[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.6399999856948853, + [Parameter::HighCut] = 0.2933000028133392, + [Parameter::DryOut] = 0.8705999851226807, + [Parameter::EarlyOut] = 0.0, + [Parameter::LateOut] = 0.6613999605178833, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.4693999886512756, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.6345999836921692, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float MGhostly[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 0.1920000016689301, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.7199999690055847, + [Parameter::LateOut] = 0.4799999892711639, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.03599999845027924, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.7080000042915344, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.1560000032186508, + [Parameter::EarlyDiffuseDelay] = 0.5986999869346619, + [Parameter::EarlyDiffuseModAmount] = 0.927899956703186, + [Parameter::EarlyDiffuseFeedback] = 0.6987000107765198, + [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 1.0, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.08399999886751175, + [Parameter::LateLineModAmount] = 0.335999995470047, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.5640000104904175, + [Parameter::LateLineModRate] = 0.2532999813556671, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 1.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.1119999960064888, + [Parameter::EqHighFreq] = 0.6413999795913696, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.8240000009536743, + [Parameter::EqHighGain] = 0.8319999575614929, + [Parameter::EqCrossSeed] = 0.1759999990463257, + [Parameter::SeedTap] = 0.7879999876022339, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.1730999946594238, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float MTappedLines[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 1.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.0, + [Parameter::LowCut] = 0.6092999577522278, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 1.0, + [Parameter::LateOut] = 0.5679999589920044, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.06399999558925629, + [Parameter::TapDecay] = 0.7719999551773071, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.8586999773979187, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.4839999973773956, + [Parameter::EarlyDiffuseDelay] = 0.2307000011205673, + [Parameter::EarlyDiffuseModAmount] = 0.6678999662399292, + [Parameter::EarlyDiffuseFeedback] = 0.7426999807357788, + [Parameter::EarlyDiffuseModRate] = 0.2866999804973602, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.515999972820282, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.2680000066757202, + [Parameter::LateLineModAmount] = 0.171999990940094, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.715999960899353, + [Parameter::LateLineModRate] = 0.2572999894618988, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.6599999666213989, + [Parameter::SeedTap] = 0.4639999866485596, + [Parameter::SeedDiffusion] = 0.3240000009536743, + [Parameter::SeedDelay] = 0.09409999847412109, + [Parameter::SeedPostDiffusion] = 0.3233000040054321, +}; + +static const float SFastAttack[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2800000011920929, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.7239999771118164, + [Parameter::DryOut] = 0.9720000028610229, + [Parameter::EarlyOut] = 0.6800000071525574, + [Parameter::LateOut] = 0.5399999618530273, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.06799999624490738, + [Parameter::TapDecay] = 0.9559999704360962, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.6520000100135803, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.5467000007629395, + [Parameter::EarlyDiffuseModAmount] = 0.3039000034332275, + [Parameter::EarlyDiffuseFeedback] = 0.5787000060081482, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.3079999983310699, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4879999756813049, + [Parameter::LateLineSize] = 0.4079999923706055, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.239999994635582, + [Parameter::LateDiffuseModAmount] = 0.1467999964952469, + [Parameter::LateLineDecay] = 0.4439999759197235, + [Parameter::LateLineModRate] = 0.0372999981045723, + [Parameter::LateDiffuseFeedback] = 0.8506999611854553, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 0.0, + [Parameter::EqLowpassEnabled] = 1.0, + [Parameter::EqLowFreq] = 0.4079999923706055, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.7439999580383301, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.2680000066757202, + [Parameter::SeedTap] = 0.3489999771118164, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float SSmallPlate[Parameter::COUNT] = { + [Parameter::Interpolation] = 0.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 1.0, + [Parameter::InputMix] = 0.2346999943256378, + [Parameter::LowCut] = 0.2933000028133392, + [Parameter::HighCut] = 0.687999963760376, + [Parameter::DryOut] = 0.8705999851226807, + [Parameter::EarlyOut] = 0.3680000007152557, + [Parameter::LateOut] = 0.5281000137329102, + [Parameter::TapEnabled] = 0.0, + [Parameter::TapCount] = 0.1959999948740005, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.9866999983787537, + [Parameter::EarlyDiffuseEnabled] = 1.0, + [Parameter::EarlyDiffuseCount] = 0.2960000038146973, + [Parameter::EarlyDiffuseDelay] = 0.3066999912261963, + [Parameter::EarlyDiffuseModAmount] = 0.143899992108345, + [Parameter::EarlyDiffuseFeedback] = 0.7706999778747559, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.8319999575614929, + [Parameter::LateDiffuseEnabled] = 0.0, + [Parameter::LateDiffuseCount] = 0.4186999797821045, + [Parameter::LateLineSize] = 0.543999969959259, + [Parameter::LateLineModAmount] = 0.2719999849796295, + [Parameter::LateDiffuseDelay] = 0.2506999969482422, + [Parameter::LateDiffuseModAmount] = 0.2480999976396561, + [Parameter::LateLineDecay] = 0.4959999918937683, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7119999527931213, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.7053999900817871, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.8906999826431274, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.3339999914169312, + [Parameter::SeedDiffusion] = 0.1850000023841858, + [Parameter::SeedDelay] = 0.2180999964475632, + [Parameter::SeedPostDiffusion] = 0.3652999997138977, +}; + +static const float SSnappyAttack[Parameter::COUNT] = { + [Parameter::Interpolation] = 1.0, + [Parameter::LowCutEnabled] = 0.0, + [Parameter::HighCutEnabled] = 0.0, + [Parameter::InputMix] = 0.3026999831199646, + [Parameter::LowCut] = 0.0, + [Parameter::HighCut] = 1.0, + [Parameter::DryOut] = 1.0, + [Parameter::EarlyOut] = 0.371999979019165, + [Parameter::LateOut] = 0.6319999694824219, + [Parameter::TapEnabled] = 1.0, + [Parameter::TapCount] = 0.5239999890327454, + [Parameter::TapDecay] = 1.0, + [Parameter::TapPredelay] = 0.0, + [Parameter::TapLength] = 0.3226999938488007, + [Parameter::EarlyDiffuseEnabled] = 0.0, + [Parameter::EarlyDiffuseCount] = 0.2119999974966049, + [Parameter::EarlyDiffuseDelay] = 0.0, + [Parameter::EarlyDiffuseModAmount] = 0.2198999971151352, + [Parameter::EarlyDiffuseFeedback] = 0.7106999754905701, + [Parameter::EarlyDiffuseModRate] = 0.2466999888420105, + [Parameter::LateMode] = 1.0, + [Parameter::LateLineCount] = 0.3279999792575836, + [Parameter::LateDiffuseEnabled] = 1.0, + [Parameter::LateDiffuseCount] = 0.03199999779462814, + [Parameter::LateLineSize] = 0.3014000058174133, + [Parameter::LateLineModAmount] = 0.1159999966621399, + [Parameter::LateDiffuseDelay] = 0.3479999899864197, + [Parameter::LateDiffuseModAmount] = 0.2547999918460846, + [Parameter::LateLineDecay] = 0.2425999939441681, + [Parameter::LateLineModRate] = 0.2292999923229218, + [Parameter::LateDiffuseFeedback] = 0.7306999564170837, + [Parameter::LateDiffuseModRate] = 0.1666999906301498, + [Parameter::EqLowShelfEnabled] = 0.0, + [Parameter::EqHighShelfEnabled] = 1.0, + [Parameter::EqLowpassEnabled] = 0.0, + [Parameter::EqLowFreq] = 0.3879999816417694, + [Parameter::EqHighFreq] = 0.5133999586105347, + [Parameter::EqCutoff] = 0.9759999513626099, + [Parameter::EqLowGain] = 0.5559999942779541, + [Parameter::EqHighGain] = 0.7680000066757202, + [Parameter::EqCrossSeed] = 0.0, + [Parameter::SeedTap] = 0.5879999995231628, + [Parameter::SeedDiffusion] = 0.2549999952316284, + [Parameter::SeedDelay] = 0.09809999912977219, + [Parameter::SeedPostDiffusion] = 0.189300000667572, +}; + +const float *AudioEffectCloudSeed2::Presets[] = { + UInit, + FXDivineInspiration, + FXLawsOfPhysics, + FXSlowBraaam, + FXTheUpsideDown, + LBigSoundStage, + LDiffusionCyclone, + LScreamIntoTheVoid, + M90sDigitalReverb, + MAiryAmbience, + MDarkPlate, + MGhostly, + MTappedLines, + SFastAttack, + SSmallPlate, + SSnappyAttack, +}; + +constexpr const char *AudioEffectCloudSeed2::PresetNames[]; diff --git a/src/effect_cloudseed2.h b/src/effect_cloudseed2.h new file mode 100644 index 000000000..5deafec68 --- /dev/null +++ b/src/effect_cloudseed2.h @@ -0,0 +1,201 @@ +/* + * CloudSeed + * Ported from https://github.com/GhostNoteAudio/CloudSeedCore + */ + +#pragma once + +#define BUFFER_SIZE 128 +#define SLOW_CLEAR_SIZE 192000 // may need to be adjusted for other Pis + +#include +#include + +#include "../CloudSeedCore/DSP/ReverbController.h" + +class AudioEffectCloudSeed2 +{ +public: + static constexpr const char *PresetNames[] = { + "Init", + "FXDivineInspiration", + "FXLawsOfPhysics", + "FXSlowBraaam", + "FXTheUpsideDown", + "LBigSoundStage", + "LDiffusionCyclone", + "LScreamIntoTheVoid", + "M90sDigitalReverb", + "MAiryAmbience", + "MDarkPlate", + "MGhostly", + "MTappedLines", + "SFastAttack", + "SSmallPlate", + "SSnappyAttack", + }; + + static constexpr unsigned presets_num = sizeof PresetNames / sizeof *PresetNames; + static const float *Presets[]; + + static std::string GetLateMode (int nValue, int nWidth) + { + return nValue ? "Post" : "Pre"; + } + + static std::string getPresetName (int nValue, int nWidth) + { + assert (nValue >= 0 && (unsigned)nValue < presets_num); + return PresetNames[nValue]; + } + + static const char *getPresetNameChar (int nValue) + { + assert (nValue >= 0 && (unsigned)nValue < presets_num); + return PresetNames[nValue]; + } + + static unsigned getIDFromPresetName(const char *presetName) + { + for (unsigned i = 0; i < presets_num; ++i) + if (strcmp(PresetNames[i], presetName) == 0) + return i; + + return 0; + } + + AudioEffectCloudSeed2(float samplerate): + bypass{}, + samplerate{samplerate}, + ramp_dt{10.0f / samplerate}, + engine{(int)samplerate}, + targetVol{}, + needBufferClear{}, + waitBufferClear{}, + needParameterLoad{}, + preset{}, + vol{} + { + } + + void setParameter(unsigned paramID, float param) + { + engine.SetParameter(paramID, param); + } + + float getParameter(unsigned paramID) + { + return engine.GetAllParameters()[paramID]; + } + + void process(float32_t* inblockL, float32_t* inblockR, uint16_t len) + { + if (targetVol == 0.0f && vol > 0.0f) + { + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + for (uint16_t i = 0; i < len; ++i) + { + vol = std::max(0.0f, vol - ramp_dt); + inblockL[i] *= vol; + inblockR[i] *= vol; + } + + return; + } + + if (needBufferClear) + { + engine.StartSlowClear(); + needBufferClear = false; + waitBufferClear = true; + } + + if (waitBufferClear) + { + if (engine.SlowClearDone(SLOW_CLEAR_SIZE)) + waitBufferClear = false; + + memset(inblockL, 0, len * sizeof *inblockL); + memset(inblockR, 0, len * sizeof *inblockR); + + return; + } + + if (needParameterLoad) + { + unsigned needParam = needParameterLoad; + unsigned paramID = Cloudseed::Parameter::COUNT - needParam; + engine.SetParameter(paramID, Presets[preset][paramID]); + needParameterLoad = needParam - 1; + + memset(inblockL, 0, len * sizeof *inblockL); + memset(inblockR, 0, len * sizeof *inblockR); + + if (!needParameterLoad) + targetVol = 1.0f; + + return; + } + + if (targetVol == 1.0f && vol < 1.0f) + { + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + for (uint16_t i = 0; i < len; ++i) + { + vol = std::min(vol + ramp_dt, 1.0f); + inblockL[i] *= vol; + inblockR[i] *= vol; + } + + return; + } + + if (bypass) return; + + if (isDisabled()) return; + + engine.Process(inblockL, inblockR, inblockL, inblockR, len); + } + + void loadPreset(unsigned p) + { + assert(p < presets_num); + preset = p; + + targetVol = 0.0f; + needBufferClear = true; + needParameterLoad = Cloudseed::Parameter::COUNT; + } + + void setNeedBufferClear() + { + needBufferClear = true; + } + + void setRampedDown() + { + vol = 0.0f; + } + + bool isDisabled() + { + double *params = engine.GetAllParameters(); + return params[Cloudseed::Parameter::DryOut] == 1.0f && + params[Cloudseed::Parameter::EarlyOut] == 0.0f && + params[Cloudseed::Parameter::LateOut] == 0.0f; + } + + std::atomic bypass; + +private: + float samplerate; + float ramp_dt; + Cloudseed::ReverbController engine; + std::atomic targetVol; + std::atomic needBufferClear; + bool waitBufferClear; + std::atomic needParameterLoad; + std::atomic preset; + + std::atomic vol; +}; diff --git a/src/effect_compressor.h b/src/effect_compressor.h new file mode 100644 index 000000000..f1aac838c --- /dev/null +++ b/src/effect_compressor.h @@ -0,0 +1,87 @@ +/* + * Chip Audette's Compressor + * https://github.com/chipaudette/OpenAudio_ArduinoLibrary/blob/master/AudioEffectCompressor_F32.h + */ + +#include + +#include "compressor.h" + +class AudioEffectCompressor +{ +public: + static const unsigned CompressorRatioInf = 31; + + AudioEffectCompressor(float samplerate): + bypass{}, + samplerate{samplerate}, + compL{samplerate}, + compR{samplerate} + {} + + void setPreGain_dB(float gain) + { + compL.setPreGain_dB(gain); + compR.setPreGain_dB(gain); + } + + void setThresh_dBFS(float thresh) + { + compL.setThresh_dBFS(thresh); + compR.setThresh_dBFS(thresh); + } + + void setCompressionRatio(float ratio) + { + ratio = ratio == CompressorRatioInf ? INFINITY : ratio; + + compL.setCompressionRatio(ratio); + compR.setCompressionRatio(ratio); + } + + void setAttack_sec(float sec) + { + compL.setAttack_sec(sec, samplerate); + compR.setAttack_sec(sec, samplerate); + } + + void setRelease_sec(float sec) + { + compL.setRelease_sec(sec, samplerate); + compR.setRelease_sec(sec, samplerate); + } + + void setMakeupGain_dB(float gain) + { + compL.setMakeupGain_dB(gain); + compR.setMakeupGain_dB(gain); + } + + void enableHPFilter(bool hpfilter) + { + compL.enableHPFilter(hpfilter); + compR.enableHPFilter(hpfilter); + } + + void resetState() + { + compL.resetStates(); + compR.resetStates(); + } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len) + { + if (bypass) return; + + compL.doCompression (blockL, len); + compR.doCompression (blockR, len); + } + + std::atomic bypass; + +private: + const float samplerate; + + Compressor compL; + Compressor compR; +}; diff --git a/src/effect_dreamdelay.cpp b/src/effect_dreamdelay.cpp new file mode 100644 index 000000000..6f2f2a553 --- /dev/null +++ b/src/effect_dreamdelay.cpp @@ -0,0 +1,177 @@ +#include "effect_dreamdelay.h" + +#include + +constexpr float32_t MAX_DELAY_TIME = 2.0f; + +AudioEffectDreamDelay::AudioEffectDreamDelay(float32_t samplerate): +bypass{}, +samplerate{samplerate}, +mode{DUAL}, +bufferSize{(size_t)(samplerate * MAX_DELAY_TIME)}, +bufferL{new float32_t[bufferSize]{}}, +bufferR{new float32_t[bufferSize]{}}, +index{}, +timeLSync{}, +timeRSync{}, +feedback{0.6f}, +lpf{samplerate, 6300.0f, 0.0f}, +tempo{120} +{ + assert(bufferL); + assert(bufferR); + + setTimeL(0.36f); + setTimeR(0.36f); + setMix(0.0f); +} + +AudioEffectDreamDelay::~AudioEffectDreamDelay() +{ + delete bufferL; + delete bufferR; +} + +static float32_t calculateTime(AudioEffectDreamDelay::Sync sync, unsigned tempo) +{ + constexpr float32_t triplet = 2.0 / 3.0; + static constexpr float32_t denominators[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 16, 16, 32, 32, 1}; + return 240.0 / tempo / denominators[(int)sync] * ((int)sync % 2 ? 1 : triplet); +} + +void AudioEffectDreamDelay::setTimeL(float32_t time) +{ + timeL = constrain(time, 0.0f, MAX_DELAY_TIME); + int offset = index - timeL * samplerate - (timeL ? 0 : 1); + if (offset < 0) offset += bufferSize; + indexDL = offset; +} + +void AudioEffectDreamDelay::setTimeR(float32_t time) +{ + timeR = constrain(time, 0.0f, MAX_DELAY_TIME); + int offset = index - timeR * samplerate - (timeR ? 0 : 1); + if (offset < 0) offset += bufferSize; + indexDR = offset; +} + +void AudioEffectDreamDelay::setTimeLSync(Sync sync) +{ + timeLSync = sync; + if (sync != SYNC_NONE) + setTimeL(calculateTime(sync, tempo)); +} + +void AudioEffectDreamDelay::setTimeRSync(Sync sync) +{ + timeRSync = sync; + if (sync != SYNC_NONE) + setTimeR(calculateTime(sync, tempo)); +} + +void AudioEffectDreamDelay::setTempo(unsigned t) +{ + tempo = constrain(t, 30u, 240u); + setTimeLSync(timeLSync); + setTimeRSync(timeRSync); +} + +void AudioEffectDreamDelay::setMix(float32_t value) +{ + mix = constrain(value, 0.0f, 1.0f); + + if (mix <= 0.5f) + { + dry = 1.0f; + wet = mix * 2.0f; + } + else + { + dry = 1.0f - ((mix - 0.5f) * 2.0f); + wet = 1.0f; + } +} + +void AudioEffectDreamDelay::process(float32_t* blockL, float32_t* blockR, uint16_t len) +{ + if (bypass) return; + + if (wet == 0.0f) return; + + switch(mode) + { + case DUAL: + for (uint16_t i = 0; i < len; i++) + { + float32_t inL = blockL[i]; + float32_t inR = blockR[i]; + + float32_t delayL = bufferL[indexDL]; + float32_t delayR = bufferR[indexDR]; + + bufferL[index] = lpf.processSampleL(inL) + delayL * feedback; + bufferR[index] = lpf.processSampleR(inR) + delayR * feedback; + + blockL[i] = inL * dry + delayL * wet; + blockR[i] = inR * dry + delayR * wet; + + indexDL = (indexDL + 1) % bufferSize; + indexDR = (indexDR + 1) % bufferSize; + index = (index + 1) % bufferSize; + } + break; + + case CROSSOVER: + for (uint16_t i = 0; i < len; i++) + { + float32_t inL = blockL[i]; + float32_t inR = blockR[i]; + + float32_t delayL = bufferL[indexDL]; + float32_t delayR = bufferR[indexDR]; + + bufferL[index] = lpf.processSampleL(inL) + delayR * feedback; + bufferR[index] = lpf.processSampleR(inR) + delayL * feedback; + + blockL[i] = inL * dry + delayL * wet; + blockR[i] = inR * dry + delayR * wet; + + indexDL = (indexDL + 1) % bufferSize; + indexDR = (indexDR + 1) % bufferSize; + index = (index + 1) % bufferSize; + } + break; + + case PINGPONG: + for (uint16_t i = 0; i < len; i++) + { + float32_t in = (blockL[i] + blockR[i]) / 2; + + float32_t delayL = bufferL[indexDL]; + float32_t delayR = bufferR[indexDR]; + + bufferL[index] = lpf.processSampleL(in) + delayR * feedback; + bufferR[index] = delayL; + + blockL[i] = in * dry + delayL * wet; + blockR[i] = in * dry + delayR * wet; + + indexDL = (indexDL + 1) % bufferSize; + indexDR = (indexDR + 1) % bufferSize; + index = (index + 1) % bufferSize; + } + break; + + default: + assert(0); + break; + } +} + +void AudioEffectDreamDelay::resetState() +{ + memset(bufferL, 0, bufferSize * sizeof *bufferL); + memset(bufferR, 0, bufferSize * sizeof *bufferR); + + lpf.resetState(); +} diff --git a/src/effect_dreamdelay.h b/src/effect_dreamdelay.h new file mode 100644 index 000000000..3eb9e22a1 --- /dev/null +++ b/src/effect_dreamdelay.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include "common.h" +#include "effect_lpf.h" + +class AudioEffectDreamDelay +{ +public: + enum Mode { DUAL, CROSSOVER, PINGPONG, MODE_UNKNOWN }; + enum Sync { SYNC_NONE, T1_1, T1_1T, T1_2, T1_2T, T1_4, T1_4T, T1_8, T1_8T, T1_16, T1_16T, T1_32, T1_32T, SYNC_UNKNOWN }; + + AudioEffectDreamDelay(float32_t samplerate); + ~AudioEffectDreamDelay(); + + void setMode(Mode m) { mode = m; } + void setTimeL(float32_t time); + void setTimeLSync(Sync sync); + void setTimeR(float32_t time); + void setTimeRSync(Sync sync); + void setFeedback(float32_t fb) { feedback = constrain(fb, 0.0f, 1.0f); } + void setHighCut(float32_t highcut) { lpf.setCutoff_Hz(highcut); } + void setTempo(unsigned t); + void setMix(float32_t mix); + + Mode getMode() { return mode; } + float32_t getTimeL() { return timeL; } + float32_t getTimeR() { return timeR; } + float32_t getFeedback() { return feedback; } + float32_t getHighCut() { return lpf.getCutoff_Hz(); } + unsigned getTempo() { return tempo; } + float32_t getMix() { return mix; } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len); + + void resetState(); + + std::atomic bypass; + +private: + float32_t samplerate; + + Mode mode; + + size_t bufferSize; + float32_t* bufferL; + float32_t* bufferR; + unsigned index; + unsigned indexDL; + unsigned indexDR; + + float32_t timeL; // Left delay time in seconds + float32_t timeR; // Right delay time in seconds + Sync timeLSync; + Sync timeRSync; + + float32_t feedback; // 0.0 - 1.0 + + AudioEffectLPF lpf; + + unsigned tempo; + + float32_t mix; + float32_t dry; + float32_t wet; +}; diff --git a/src/effect_lpf.h b/src/effect_lpf.h new file mode 100644 index 000000000..46b1148c6 --- /dev/null +++ b/src/effect_lpf.h @@ -0,0 +1,130 @@ +/* + * Stereo Low Pass Filter + * Ported from (https://github.com/jnonis/MiniDexed) + */ + +#pragma once + +class AudioEffectLPF +{ +public: + static constexpr float32_t MIN_CUTOFF = 0.00001f; + static constexpr float32_t MAX_CUTOFF = 20000.0f; + static constexpr float32_t MIN_RES = 0.0f; + static constexpr float32_t MAX_RES = 1.0f; + + struct LPFState + { + float32_t y1; + float32_t y2; + float32_t y3; + float32_t y4; + float32_t oldx; + float32_t oldy1; + float32_t oldy2; + float32_t oldy3; + }; + + AudioEffectLPF(float32_t samplerate, float32_t cutoff_Hz, float32_t resonance): + samplerate{samplerate}, + cutoff{constrain(cutoff_Hz, MIN_CUTOFF, MAX_CUTOFF)}, + resonance{constrain(resonance, MIN_RES, MAX_RES)}, + stateL{}, + stateR{} + { + recalculate(); + } + + float32_t getCutoff_Hz() { return cutoff; } + + void setCutoff_Hz(float32_t value) + { + cutoff = constrain(value, MIN_CUTOFF, MAX_CUTOFF); + recalculate(); + } + + void setResonance(float32_t value) + { + resonance = constrain(value, MIN_RES, MAX_RES); + recalculate(); + } + + float32_t processSampleL(float32_t input) + { + return processSample(input, &stateL); + } + + float32_t processSampleR(float32_t input) + { + return processSample(input, &stateR); + } + + void process(float32_t* blockL, float32_t* blockR, uint16_t len) + { + for (int i = 0; i < len; i++) + { + blockL[i] = processSample(blockL[i], &stateL); + blockR[i] = processSample(blockR[i], &stateR); + } + } + + void resetState() + { + stateL = {}; + stateR = {}; + } + +private: + void recalculate() + { + float32_t f = (cutoff + cutoff) / samplerate; + p = f * (1.8 - (0.8 * f)); + k = p + p - 1.0; + + float32_t t = (1.0 - p) * 1.386249; + float32_t t2 = 12.0 + t * t; + r = resonance * (t2 + 6.0 * t) / (t2 - 6.0 * t); + } + + float32_t processSample(float32_t input, LPFState* state) + { + float32_t y1 = state->y1; + float32_t y2 = state->y2; + float32_t y3 = state->y3; + float32_t y4 = state->y4; + float32_t oldx = state->oldx; + float32_t oldy1 = state->oldy1; + float32_t oldy2 = state->oldy2; + float32_t oldy3 = state->oldy3; + + // Process input + float32_t x = input - r * y4; + + // Four cascaded one pole filters (bilinear transform) + y1 = x * p + oldx * p - k * y1; + y2 = y1 * p + oldy1 * p - k * y2; + y3 = y2 * p + oldy2 * p - k * y3; + y4 = y3 * p + oldy3 * p - k * y4; + + // Clipper band limited sigmoid + y4 -= (y4 * y4 * y4) / 6.0; + + state->y1 = y1; + state->y2 = y2; + state->y3 = y3; + state->y4 = y4; + state->oldx = x; + state->oldy1 = y1; + state->oldy2 = y2; + state->oldy3 = y3; + + return y4; + } + + float32_t samplerate; + float32_t cutoff; + float32_t resonance; + float32_t r, p, k; + LPFState stateL; + LPFState stateR; +}; diff --git a/src/effect_mixer.hpp b/src/effect_mixer.hpp index 9cf5070c5..6d5483ea6 100644 --- a/src/effect_mixer.hpp +++ b/src/effect_mixer.hpp @@ -5,8 +5,8 @@ #define effect_mixer_h_ #include -#include -#include "arm_math.h" +#include +#include #define UNITY_GAIN 1.0f #define MAX_GAIN 1.0f @@ -15,10 +15,42 @@ #define MAX_PANORAMA 1.0f #define MIN_PANORAMA 0.0f +void inline scale_ramp_f32( + const float32_t * pSrc, + float32_t * pScale, + float32_t dScale, + float32_t ramp, + float32_t * pDst, + uint32_t blockSize) +{ + uint32_t blkCnt; /* Loop counter */ + float32_t scale = *pScale; + + blkCnt = blockSize; + + while (blkCnt > 0U) + { + if (scale != dScale) + { + scale = dScale > scale ? + fmin(dScale, scale + ramp): + fmax(dScale, scale - ramp); + } + + *pDst++ = *pSrc++ * scale; + + blkCnt--; + } + + *pScale = scale; +} + + template class AudioMixer { public: - AudioMixer(uint16_t len) + AudioMixer(uint16_t len, float32_t samplerate): + ramp{10.0f / samplerate} // 100ms { buffer_length=len; for (uint8_t i=0; i class AudioMixer gain = MAX_GAIN; else if (gain < MIN_GAIN) gain = MIN_GAIN; - multiplier[channel] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + multiplier[channel] = powf(gain, 2); } void gain(float32_t gain) { + float32_t gain4 = powf(gain, 2); + for (uint8_t i = 0; i < NN; i++) { if (gain > MAX_GAIN) gain = MAX_GAIN; else if (gain < MIN_GAIN) gain = MIN_GAIN; - multiplier[i] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + multiplier[i] = gain4; } } @@ -81,17 +115,20 @@ template class AudioMixer float32_t multiplier[NN]; float32_t* sumbufL; uint16_t buffer_length; + const float32_t ramp; }; template class AudioStereoMixer : public AudioMixer { public: - AudioStereoMixer(uint16_t len) : AudioMixer(len) + AudioStereoMixer(uint16_t len, float32_t samplerate) : AudioMixer(len, samplerate) { for (uint8_t i=0; i class AudioStereoMixer : public AudioMixer delete [] sumbufR; } + void gain(uint8_t channel, float32_t gain) + { + if (channel >= NN) return; + + if (gain > MAX_GAIN) + gain = MAX_GAIN; + else if (gain < MIN_GAIN) + gain = MIN_GAIN; + multiplier[channel] = powf(gain, 2); + + mp_w[channel][0] = multiplier[channel] * panorama[channel][0]; + mp_w[channel][1] = multiplier[channel] * panorama[channel][1]; + } + + void gain(float32_t gain) + { + float32_t gain4 = powf(gain, 2); + + for (uint8_t i = 0; i < NN; i++) + { + if (gain > MAX_GAIN) + gain = MAX_GAIN; + else if (gain < MIN_GAIN) + gain = MIN_GAIN; + multiplier[i] = gain4; + + mp_w[i][0] = multiplier[i] * panorama[i][0]; + mp_w[i][1] = multiplier[i] * panorama[i][1]; + } + } + void pan(uint8_t channel, float32_t pan) { if (channel >= NN) return; @@ -113,8 +181,11 @@ template class AudioStereoMixer : public AudioMixer pan = MIN_PANORAMA; // From: https://stackoverflow.com/questions/67062207/how-to-pan-audio-sample-data-naturally - panorama[channel][0]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); - panorama[channel][1]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); + panorama[channel][0]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); + panorama[channel][1]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); + + mp_w[channel][0] = multiplier[channel] * panorama[channel][0]; + mp_w[channel][1] = multiplier[channel] * panorama[channel][1]; } void doAddMix(uint8_t channel, float32_t* in) @@ -123,12 +194,25 @@ template class AudioStereoMixer : public AudioMixer assert(in); - // left - arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, buffer_length); - arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); - // right - arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, buffer_length); - arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); + if (mp[channel][0] != 0.0f || mp_w[channel][0] != 0.0f) + { + if (mp[channel][0] == mp_w[channel][0]) + arm_scale_f32(in, mp[channel][0], tmp, buffer_length); + else + scale_ramp_f32(in, &mp[channel][0], mp_w[channel][0], ramp, tmp, buffer_length); + + arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); + } + + if (mp[channel][1] != 0.0f || mp_w[channel][1] != 0.0f) + { + if (mp[channel][1] == mp_w[channel][1]) + arm_scale_f32(in, mp[channel][1], tmp, buffer_length); + else + scale_ramp_f32(in, &mp[channel][1], mp_w[channel][1], ramp, tmp, buffer_length); + + arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); + } } void getMix(float32_t* bufferL, float32_t* bufferR) @@ -165,7 +249,10 @@ template class AudioStereoMixer : public AudioMixer using AudioMixer::sumbufL; using AudioMixer::multiplier; using AudioMixer::buffer_length; + using AudioMixer::ramp; float32_t panorama[NN][2]; + float32_t mp[NN][2]; + float32_t mp_w[NN][2]; float32_t* sumbufR; }; diff --git a/src/effect_platervbstereo.cpp b/src/effect_platervbstereo.cpp index ce2af1e48..012a2cc52 100644 --- a/src/effect_platervbstereo.cpp +++ b/src/effect_platervbstereo.cpp @@ -31,9 +31,9 @@ */ -#include +#include #include -#include +#include #include "effect_platervbstereo.h" #define INP_ALLP_COEFF (0.65f) // default input allpass coeff @@ -83,8 +83,11 @@ const int16_t AudioWaveformSine[257] = { -4808, -4011, -3212, -2410, -1608, -804, 0 }; -AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) +AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate): +bypass{} { + set_mix(0.0f); + input_attn = 0.5f; in_allp_k = INP_ALLP_COEFF; @@ -152,13 +155,68 @@ AudioEffectPlateReverb::AudioEffectPlateReverb(float32_t samplerate) lfo1_adder = (UINT32_MAX + 1)/(samplerate * LFO1_FREQ_HZ); lfo2_phase_acc = 0; lfo2_adder = (UINT32_MAX + 1)/(samplerate * LFO2_FREQ_HZ); - - reverb_level = 0.0f; } // #define sat16(n, rshift) signed_saturate_rshift((n), 16, (rshift)) -void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR, uint16_t len) +void AudioEffectPlateReverb::reset() +{ + memset(in_allp1_bufL, 0, sizeof(in_allp1_bufL)); + memset(in_allp2_bufL, 0, sizeof(in_allp2_bufL)); + memset(in_allp3_bufL, 0, sizeof(in_allp3_bufL)); + memset(in_allp4_bufL, 0, sizeof(in_allp4_bufL)); + in_allp1_idxL = 0; + in_allp2_idxL = 0; + in_allp3_idxL = 0; + in_allp4_idxL = 0; + + memset(in_allp1_bufR, 0, sizeof(in_allp1_bufR)); + memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR)); + memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR)); + memset(in_allp4_bufR, 0, sizeof(in_allp4_bufR)); + in_allp1_idxR = 0; + in_allp2_idxR = 0; + in_allp3_idxR = 0; + in_allp4_idxR = 0; + + memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf)); + memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf)); + memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf)); + memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf)); + lp_allp1_idx = 0; + lp_allp2_idx = 0; + lp_allp3_idx = 0; + lp_allp4_idx = 0; + + lp_allp_out = 0.0f; + + memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf)); + memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf)); + memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf)); + memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf)); + lp_dly1_idx = 0; + lp_dly2_idx = 0; + lp_dly3_idx = 0; + lp_dly4_idx = 0; + + lpf1 = 0.0f; + lpf2 = 0.0f; + lpf3 = 0.0f; + lpf4 = 0.0f; + + hpf1 = 0.0f; + hpf2 = 0.0f; + hpf3 = 0.0f; + hpf4 = 0.0f; + + master_lowpass_l = 0.0f; + master_lowpass_r = 0.0f; + + lfo1_phase_acc = 0; + lfo2_phase_acc = 0; +} + +void AudioEffectPlateReverb::process(const float32_t *inblockL, const float32_t *inblockR, float32_t *outblockL, float32_t *outblockR, uint16_t len) { float32_t input, acc, temp1, temp2; uint16_t temp16; @@ -169,36 +227,10 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t int32_t y0, y1; int64_t y; uint32_t idx; - static bool cleanup_done = false; - // handle bypass, 1st call will clean the buffers to avoid continuing the previous reverb tail - if (bypass) - { - if (!cleanup_done) - { - memset(in_allp1_bufL, 0, sizeof(in_allp1_bufL)); - memset(in_allp2_bufL, 0, sizeof(in_allp2_bufL)); - memset(in_allp3_bufL, 0, sizeof(in_allp3_bufL)); - memset(in_allp4_bufL, 0, sizeof(in_allp4_bufL)); - memset(in_allp1_bufR, 0, sizeof(in_allp1_bufR)); - memset(in_allp2_bufR, 0, sizeof(in_allp2_bufR)); - memset(in_allp3_bufR, 0, sizeof(in_allp3_bufR)); - memset(in_allp4_bufR, 0, sizeof(in_allp4_bufR)); - memset(lp_allp1_buf, 0, sizeof(lp_allp1_buf)); - memset(lp_allp2_buf, 0, sizeof(lp_allp2_buf)); - memset(lp_allp3_buf, 0, sizeof(lp_allp3_buf)); - memset(lp_allp4_buf, 0, sizeof(lp_allp4_buf)); - memset(lp_dly1_buf, 0, sizeof(lp_dly1_buf)); - memset(lp_dly2_buf, 0, sizeof(lp_dly2_buf)); - memset(lp_dly3_buf, 0, sizeof(lp_dly3_buf)); - memset(lp_dly4_buf, 0, sizeof(lp_dly4_buf)); - - cleanup_done = true; - } - - return; - } - cleanup_done = false; + if (bypass) return; + + if (wet == 0.0f) return; rv_time = rv_time_k; @@ -405,7 +437,7 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t temp1 = acc - master_lowpass_l; master_lowpass_l += temp1 * master_lowpass_f; - rvbblockL[i] = master_lowpass_l; + outblockL[i] = dry * inblockL[i] + wet * master_lowpass_l; // Channel R #ifdef TAP1_MODULATED @@ -449,6 +481,6 @@ void AudioEffectPlateReverb::doReverb(const float32_t* inblockL, const float32_t temp1 = acc - master_lowpass_r; master_lowpass_r += temp1 * master_lowpass_f; - rvbblockR[i] = master_lowpass_r; + outblockR[i] = dry * inblockR[i] + wet * master_lowpass_r; } } diff --git a/src/effect_platervbstereo.h b/src/effect_platervbstereo.h index 23538c460..eb5286cf7 100644 --- a/src/effect_platervbstereo.h +++ b/src/effect_platervbstereo.h @@ -44,7 +44,8 @@ #ifndef _EFFECT_PLATERVBSTEREO_H #define _EFFECT_PLATERVBSTEREO_H -#include +#include +#include #include #include "common.h" @@ -60,7 +61,7 @@ class AudioEffectPlateReverb { public: AudioEffectPlateReverb(float32_t samplerate); - void doReverb(const float32_t* inblockL, const float32_t* inblockR, float32_t* rvbblockL, float32_t* rvbblockR,uint16_t len); + void process(const float32_t *inblockL, const float32_t *inblockR, float32_t *outblockL, float32_t *outblockR, uint16_t len); void size(float n) { @@ -99,19 +100,30 @@ class AudioEffectPlateReverb loop_allp_k = n; } - void level(float n) + float32_t get_size(void) {return rv_time_k;} + + void set_mix(float32_t value) { - reverb_level = constrain(n, 0.0f, 1.0f); + mix = constrain(value, 0.0f, 1.0f); + + if (mix <= 0.5f) + { + dry = 1.0f; + wet = mix * 2.0f; + } + else + { + dry = 1.0f - ((mix - 0.5f) * 2.0f); + wet = 1.0f; + } } - float32_t get_size(void) {return rv_time_k;} - bool get_bypass(void) {return bypass;} - void set_bypass(bool state) {bypass = state;}; - void tgl_bypass(void) {bypass ^=1;} - float32_t get_level(void) {return reverb_level;} + void reset(); + + std::atomic bypass; + private: - bool bypass = false; - float32_t reverb_level; + float32_t mix, dry, wet; float32_t input_attn; float32_t in_allp_k; // input allpass coeff diff --git a/src/effect_ykchorus.h b/src/effect_ykchorus.h new file mode 100644 index 000000000..f400f6731 --- /dev/null +++ b/src/effect_ykchorus.h @@ -0,0 +1,77 @@ +/* + * YK Chorus Port + * Ported from https://github.com/SpotlightKid/ykchorus + * Ported from https://github.com/jnonis/MiniDexed + */ + +#pragma once + +#include + +#include "ykchorus/ChorusEngine.h" + +class AudioEffectYKChorus +{ +public: + AudioEffectYKChorus(float samplerate): + bypass{}, + engine{samplerate} + { + setChorus1(true); + setChorus2(true); + setChorus1LFORate(0.5f); + setChorus2LFORate(0.83f); + setMix(0.0f); + } + + bool getChorus1() { return engine.isChorus1Enabled; } + bool getChorus2() { return engine.isChorus2Enabled; } + + void setChorus1(bool enable) { engine.setEnablesChorus(enable, engine.isChorus2Enabled); } + void setChorus2(bool enable) { engine.setEnablesChorus(engine.isChorus1Enabled, enable); } + + float getChorus1Rate() { return engine.chorus1L->rate; } + float getChorus2Rate() { return engine.chorus2L->rate; } + + void setChorus1LFORate(float32_t rate) { engine.setChorus1LfoRate(rate); } + void setChorus2LFORate(float32_t rate) { engine.setChorus2LfoRate(rate); } + + float32_t getMix() { return mix; } + + void setMix(float32_t value) + { + mix = constrain(value, 0.0f, 1.0f); + + if (mix <= 0.5f) + { + dry = 1.0f; + wet = mix * 2.0f; + } + else + { + dry = 1.0f - ((mix - 0.5f) * 2.0f); + wet = 1.0f; + } + } + + void process(float32_t* inblockL, float32_t* inblockR, uint16_t len) + { + if (bypass) return; + + if (wet == 0.0f) return; + + if (!engine.isChorus1Enabled && !engine.isChorus2Enabled) return; + + for (uint16_t i = 0; i < len; i++) + { + engine.process(dry, wet, inblockL++, inblockR++); + } + } + + std::atomic bypass; + +private: + ChorusEngine engine; + + float32_t mix, dry, wet; +}; diff --git a/src/kernel.cpp b/src/kernel.cpp index c6c86d9f2..1d71b5d3b 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include "usbminidexedmidigadget.h" @@ -50,6 +50,22 @@ CKernel::~CKernel(void) s_pThis = 0; } +static void SystemThrottledHandler (TSystemThrottledState CurrentState, void *pParam) +{ + LOGNOTE ("System Throttled"); + + if (CurrentState & SystemStateUnderVoltageOccurred) + LOGNOTE ("SystemStateUnderVoltageOccurred"); + if (CurrentState & SystemStateFrequencyCappingOccurred) + LOGNOTE ("SystemStateFrequencyCappingOccurred"); + if (CurrentState & SystemStateThrottlingOccurred) + LOGNOTE ("SystemStateThrottlingOccurred"); + if (CurrentState & SystemStateSoftTempLimitOccurred) + LOGNOTE ("SystemStateSoftTempLimitOccurred"); + + CCPUThrottle::Get ()->DumpStatus (); +} + bool CKernel::Initialize (void) { if (!CStdlibAppStdio::Initialize ()) @@ -70,7 +86,15 @@ bool CKernel::Initialize (void) } m_Config.Load (); - + + m_CPUThrottle.DumpStatus (); + if (m_Config.GetLogThrottling ()) + { + m_CPUThrottle.RegisterSystemThrottledHandler ( SystemStateUnderVoltageOccurred | + SystemStateFrequencyCappingOccurred | SystemStateThrottlingOccurred | + SystemStateSoftTempLimitOccurred, SystemThrottledHandler, 0); + } + unsigned nSPIMaster = m_Config.GetSPIBus(); unsigned nSPIMode = m_Config.GetSPIMode(); unsigned long nSPIClock = 1000 * m_Config.GetSPIClockKHz(); diff --git a/src/midi.h b/src/midi.h index 0e50f19b1..7794c7952 100644 --- a/src/midi.h +++ b/src/midi.h @@ -35,13 +35,14 @@ #define MIDI_CC_PAN_POSITION 10 #define MIDI_CC_EXPRESSION 11 #define MIDI_CC_BANK_SELECT_LSB 32 -#define MIDI_CC_BANK_SUSTAIN 64 +#define MIDI_CC_SUSTAIN 64 #define MIDI_CC_PORTAMENTO 65 #define MIDI_CC_SOSTENUTO 66 #define MIDI_CC_HOLD2 69 #define MIDI_CC_RESONANCE 71 #define MIDI_CC_FREQUENCY_CUTOFF 74 -#define MIDI_CC_REVERB_LEVEL 91 +#define MIDI_CC_EFFECT1_SEND 91 +#define MIDI_CC_EFFECT2_SEND 92 #define MIDI_CC_DETUNE_LEVEL 94 #define MIDI_CC_ALL_SOUND_OFF 120 #define MIDI_CC_ALL_NOTES_OFF 123 @@ -53,4 +54,14 @@ #define MIDI_PROGRAM_CHANGE 0b1100 #define MIDI_PITCH_BEND 0b1110 +static const uint16_t MIDI_EQ_HZ[] = { + 20, 22, 25, 28, 32, 36, 40, 45, 50, 56, + 63, 70, 80, 90, 100, 110, 125, 140, 160, 180, + 200, 225, 250, 280, 315, 355, 400, 450, 500, 560, + 630, 700, 800, 900, 1000, 1100, 1200, 1400, 1600, 1800, + 2000, 2200, 2500, 2800, 3200, 3600, 4000, 4500, 5000, 5600, + 6300, 7000, 8000, 9000, 10000, 11000, 12000, 14000, 16000, 18000, + 20000 +}; + #endif diff --git a/src/mididevice.cpp b/src/mididevice.cpp index f6891a11a..a298ce990 100644 --- a/src/mididevice.cpp +++ b/src/mididevice.cpp @@ -22,6 +22,7 @@ // #include +#include #include "mididevice.h" #include "minidexed.h" #include "config.h" @@ -57,7 +58,8 @@ CMIDIDevice::TDeviceMap CMIDIDevice::s_DeviceMap; CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI) : m_pSynthesizer (pSynthesizer), m_pConfig (pConfig), - m_pUI (pUI) + m_pUI (pUI), + m_pRouteMap () { for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) { @@ -209,14 +211,25 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign m_MIDISpinLock.Acquire (); + u8 ucCable = nCable; u8 ucStatus = pMessage[0]; u8 ucChannel = ucStatus & 0x0F; u8 ucType = ucStatus >> 4; + u8 ucP1 = pMessage[1]; + u8 ucP2 = nLength >= 3 ? pMessage[2] : 0xFF; + bool bSkip = false; + if (m_pRouteMap) + GetRoutedMIDI (m_pRouteMap, this, &ucCable, &ucChannel, &ucType, &ucP1, &ucP2, &bSkip); + + if (bSkip) + { + // skip (and release mutex at the end) + } // GLOBAL MIDI SYSEX // Set MIDI Channel for TX816/TX216 SysEx; in MiniDexed, we interpret the device parameter as the number of the TG (unlike the TX816/TX216 which has a hardware switch to select the TG) - if (nLength == 7 && + else if (nLength == 7 && pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN && pMessage[1] == 0x43 && // pMessage[2] & 0x0F = TG number @@ -258,10 +271,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { // Convert LSB/MSB to 14-bit integer volume uint32_t nMasterVolume=((pMessage[5] & 0x7F) | ((pMessage[6] & 0x7F) <<7)); - // Convert to value between 0.0 and 1.0 - float32_t fMasterVolume = (float32_t)nMasterVolume / 16384.0; - //printf("Master volume: %f (%d)\n",fMasterVolume, nMasterVolume); - m_pSynthesizer->setMasterVolume(fMasterVolume); + m_pSynthesizer->SetParameter (CMiniDexed::ParameterMasterVolume, maplong (nMasterVolume, 0, 16383, 0, 127)); } else { @@ -275,13 +285,13 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { if ((ucChannel == nPerfCh) || (nPerfCh == OmniMode)) { - if (pMessage[1] == MIDI_CC_BANK_SELECT_MSB) + if (ucP1 == MIDI_CC_BANK_SELECT_MSB) { - m_pSynthesizer->BankSelectMSBPerformance (pMessage[2]); + m_pSynthesizer->BankSelectMSBPerformance (ucP2); } - else if (pMessage[1] == MIDI_CC_BANK_SELECT_LSB) + else if (ucP1 == MIDI_CC_BANK_SELECT_LSB) { - m_pSynthesizer->BankSelectLSBPerformance (pMessage[2]); + m_pSynthesizer->BankSelectLSBPerformance (ucP2); } else { @@ -303,7 +313,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } if (nLength == 3) { - m_pUI->UIMIDICmdHandler (ucChannel, ucType, pMessage[1], pMessage[2]); + m_pUI->UIMIDICmdHandler (ucChannel, ucType, ucP1, ucP2); } break; @@ -313,7 +323,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign { break; } - m_pUI->UIMIDICmdHandler (ucChannel, ucType, pMessage[1], pMessage[2]); + m_pUI->UIMIDICmdHandler (ucChannel, ucType, ucP1, ucP2); break; case MIDI_PROGRAM_CHANGE: @@ -325,7 +335,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign if ((ucChannel == nPerfCh) || (nPerfCh == OmniMode)) { //printf("Performance Select Channel %d\n", nPerfCh); - m_pSynthesizer->ProgramChangePerformance (pMessage[1]); + m_pSynthesizer->ProgramChangePerformance (ucP1); } } } @@ -338,6 +348,10 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN) { uint8_t ucSysExChannel = (pMessage[2] & 0x0F); for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators(); nTG++) { + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, nTG) == 0) + continue; + if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode) { LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG); @@ -459,6 +473,10 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } } else { for (unsigned nTG = 0; nTG < m_pConfig->GetToneGenerators() && !bSystemCCHandled; nTG++) { + + if (m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterEnabled, nTG) == 0) + continue; + if ( m_ChannelMap[nTG] == ucChannel || m_ChannelMap[nTG] == OmniMode) { switch (ucType) @@ -469,17 +487,17 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - if (pMessage[2] > 0) + if (ucP2 > 0) { - if (pMessage[2] <= 127) + if (ucP2 <= 127) { - m_pSynthesizer->keydown (pMessage[1], - pMessage[2], nTG); + m_pSynthesizer->keydown (ucP1, + ucP2, nTG); } } else { - m_pSynthesizer->keyup (pMessage[1], nTG); + m_pSynthesizer->keyup (ucP1, nTG); } break; @@ -489,12 +507,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - m_pSynthesizer->keyup (pMessage[1], nTG); + m_pSynthesizer->keyup (ucP1, nTG); break; case MIDI_CHANNEL_AFTERTOUCH: - m_pSynthesizer->setAftertouch (pMessage[1], nTG); + m_pSynthesizer->setAftertouch (ucP1, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; @@ -504,33 +522,36 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - switch (pMessage[1]) + switch (ucP1) { case MIDI_CC_MODULATION: - m_pSynthesizer->setModWheel (pMessage[2], nTG); + m_pSynthesizer->setModWheel (ucP2, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; case MIDI_CC_FOOT_PEDAL: - m_pSynthesizer->setFootController (pMessage[2], nTG); + m_pSynthesizer->setFootController (ucP2, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; case MIDI_CC_PORTAMENTO_TIME: - m_pSynthesizer->setPortamentoTime (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->setPortamentoTime (maplong (ucP2, 0, 127, 0, 99), nTG); break; case MIDI_CC_BREATH_CONTROLLER: - m_pSynthesizer->setBreathController (pMessage[2], nTG); + m_pSynthesizer->setBreathController (ucP2, nTG); m_pSynthesizer->ControllersRefresh (nTG); break; case MIDI_CC_VOLUME: - m_pSynthesizer->SetVolume (pMessage[2], nTG); + m_pSynthesizer->SetVolume (ucP2, nTG); break; case MIDI_CC_PAN_POSITION: - m_pSynthesizer->SetPan (pMessage[2], nTG); + if (m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterTGLink, nTG)) + break; + + m_pSynthesizer->SetPan (ucP2, nTG); break; case MIDI_CC_EXPRESSION: @@ -541,43 +562,50 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; case MIDI_CC_BANK_SELECT_MSB: - m_pSynthesizer->BankSelectMSB (pMessage[2], nTG); + m_pSynthesizer->BankSelectMSB (ucP2, nTG); break; case MIDI_CC_BANK_SELECT_LSB: - m_pSynthesizer->BankSelectLSB (pMessage[2], nTG); + m_pSynthesizer->BankSelectLSB (ucP2, nTG); break; - case MIDI_CC_BANK_SUSTAIN: - m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG); + case MIDI_CC_SUSTAIN: + m_pSynthesizer->setSustain (ucP2 >= 64, nTG); break; case MIDI_CC_SOSTENUTO: - m_pSynthesizer->setSostenuto (pMessage[2] >= 64, nTG); + m_pSynthesizer->setSostenuto (ucP2 >= 64, nTG); break; case MIDI_CC_PORTAMENTO: - m_pSynthesizer->setPortamentoMode (pMessage[2] >= 64, nTG); + m_pSynthesizer->setPortamentoMode (ucP2 >= 64, nTG); break; case MIDI_CC_HOLD2: - m_pSynthesizer->setHoldMode (pMessage[2] >= 64, nTG); + m_pSynthesizer->setHoldMode (ucP2 >= 64, nTG); break; case MIDI_CC_RESONANCE: - m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->SetResonance (maplong (ucP2, 0, 127, 0, 99), nTG); break; case MIDI_CC_FREQUENCY_CUTOFF: - m_pSynthesizer->SetCutoff (maplong (pMessage[2], 0, 127, 0, 99), nTG); + m_pSynthesizer->SetCutoff (maplong (ucP2, 0, 127, 0, 99), nTG); break; - - case MIDI_CC_REVERB_LEVEL: - m_pSynthesizer->SetReverbSend (maplong (pMessage[2], 0, 127, 0, 99), nTG); + + case MIDI_CC_EFFECT1_SEND: + m_pSynthesizer->SetFX1Send (maplong (ucP2, 0, 127, 0, 99), nTG); break; - + + case MIDI_CC_EFFECT2_SEND: + m_pSynthesizer->SetFX2Send (maplong (ucP2, 0, 127, 0, 99), nTG); + break; + case MIDI_CC_DETUNE_LEVEL: - if (pMessage[2] == 0) + if (m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterTGLink, nTG)) + break; + + if (ucP2 == 0) { // 0 to 127, with 0 being no detune effect applied at all m_pSynthesizer->SetMasterTune (0, nTG); @@ -585,12 +613,12 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign else { // Scale to -99 to +99 cents - m_pSynthesizer->SetMasterTune (maplong (pMessage[2], 1, 127, -99, 99), nTG); + m_pSynthesizer->SetMasterTune (maplong (ucP2, 1, 127, -99, 99), nTG); } break; case MIDI_CC_ALL_SOUND_OFF: - m_pSynthesizer->panic (pMessage[2], nTG); + m_pSynthesizer->panic (ucP2, nTG); break; case MIDI_CC_ALL_NOTES_OFF: @@ -599,7 +627,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign // "Receivers should ignore an All Notes Off message while Omni is on (Modes 1 & 2)" if (!m_pConfig->GetIgnoreAllNotesOff () && m_ChannelMap[nTG] != OmniMode) { - m_pSynthesizer->notesOff (pMessage[2], nTG); + m_pSynthesizer->notesOff (ucP2, nTG); } break; @@ -638,7 +666,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign // so it is possible to break out of the main TG loop too. // Note: We handle this here so we get the TG MIDI channel checking. if (!bSystemCCChecked) { - bSystemCCHandled = HandleMIDISystemCC(pMessage[1], pMessage[2]); + bSystemCCHandled = HandleMIDISystemCC(ucP1, ucP2); bSystemCCChecked = true; } break; @@ -649,7 +677,7 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign // do program change only if enabled in config and not in "Performance Select Channel" mode if( m_pConfig->GetMIDIRXProgramChange() && ( m_pSynthesizer->GetPerformanceSelectChannel() == Disabled) ) { //printf("Program Change to %d (%d)\n", ucChannel, m_pSynthesizer->GetPerformanceSelectChannel()); - m_pSynthesizer->ProgramChange (pMessage[1], nTG); + m_pSynthesizer->ProgramChange (ucP1, nTG); } break; @@ -659,8 +687,8 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign break; } - s16 nValue = pMessage[1]; - nValue |= (s16) pMessage[2] << 7; + s16 nValue = ucP1; + nValue |= (s16) ucP2 << 7; nValue -= 0x2000; m_pSynthesizer->setPitchbend (nValue, nTG); @@ -672,6 +700,9 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign } } } + + if (m_pRouteMap) + MIDIListener(ucCable, ucChannel, ucType, ucP1, ucP2); } m_MIDISpinLock.Release (); } @@ -735,6 +766,11 @@ bool CMIDIDevice::HandleMIDISystemCC(const u8 ucCC, const u8 ucCCval) return false; } +void CMIDIDevice::SetRouteMap (TMIDIRoute *pRouteMap) +{ + m_pRouteMap = pRouteMap; +} + void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG) { @@ -844,3 +880,102 @@ void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const std::string& de LOGWARN("No device found in s_DeviceMap for name: %s", deviceName.c_str()); } } + +void CMIDIDevice::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ +} + +void CMIDIDevice::s_HandleTimerTimeout(TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + CMIDIDevice *pDevice = static_cast(pParam); + TMIDIRoute *pRoute = static_cast(pContext); + TMIDIRoute *pTarget = pRoute + pRoute->ucTimerTarget; + + pRoute->hTimer = 0; + pRoute->bGroupActive = false; + pRoute->bGroupHold = false; + if (!pTarget->bSkip) + pDevice->MIDIListener (pTarget->ucSCable, pTarget->ucDCh, pTarget->ucDType, pTarget->ucDP1, pTarget->ucDP2); +} + +static bool RouteMatch (u8 ucSP, u8 ucP) +{ + return ucSP == ucP || + ucSP == 0xFF || + ucSP == TMIDIRoute::LtCenter && ucP < 64 || + ucSP == TMIDIRoute::GtCenter && ucP > 64 || + ucSP == TMIDIRoute::Betw00n07 && ucP >= 0 && ucP <= 7 || + ucSP == TMIDIRoute::Betw08n15 && ucP >= 8 && ucP <= 15 || + ucSP == TMIDIRoute::Betw16n23 && ucP >= 16 && ucP <= 23; +} + +void GetRoutedMIDI (TMIDIRoute *pRouteMap, CMIDIDevice *pDevice, u8 *pCable, u8 *pCh, u8 *pType, u8 *pP1, u8 *pP2, bool *bSkip) +{ + assert (pRouteMap); + for (TMIDIRoute *r = pRouteMap; r->ucSCable != 0xFF ; r++) + { + if (r->ucSCable == *pCable && + (r->ucSCh == *pCh || r->ucSCh >= 16) && + (r->ucSType == *pType || r->ucSType >= 16) && + RouteMatch (r->ucSP1, *pP1) && + RouteMatch (r->ucSP2, *pP2) + ) + { + if (r->usTimerExpire) + r->hTimer = CTimer::Get ()->StartKernelTimer (MSEC2HZ(r->usTimerExpire), CMIDIDevice::s_HandleTimerTimeout, pDevice, r); + + if (r->usTimerExpire || r->bGroupHead) + r->bGroupActive = true; + + if (r->bSkip) { + *bSkip = true; + return; + } + + if (r->bGroup) { + TMIDIRoute *parent = r - 1; + for (; parent > pRouteMap && parent->bGroup; parent--); + + if (parent->hTimer) { + CTimer::Get ()->CancelKernelTimer (parent->hTimer); + parent->hTimer = 0; + } + + if (!r->bGroupHold) + parent->bGroupHold = false; + + if (!parent->bGroupActive && !parent->bGroupHold) { + // skip at the end if not captured by other routes + *bSkip = true; + continue; + } + + // hold the group for bGroupHold routes + if (r->bGroupHold) + parent->bGroupHold = true; + + parent->bGroupActive = false; + } + + *pCh = r->ucDCh; + *pType = r->ucDType; + if (r->ucDP1 <= 127) + *pP1 = r->ucDP1; + if (r->ucDP1 == TMIDIRoute::P2) + *pP1 = *pP2; + if (r->ucDP2 <= 127) + *pP2 = r->ucDP2; + if (r->bToggle) + r->ucDP2 = r->ucDP2 ? 0x0 : 0x7F; + *bSkip = false; + return; + } + } +} + +TMIDIRoute::~TMIDIRoute () +{ + if (hTimer) + CTimer::Get ()->CancelKernelTimer (hTimer); + hTimer = 0; +} diff --git a/src/mididevice.h b/src/mididevice.h index 7da871783..f76f70bd9 100644 --- a/src/mididevice.h +++ b/src/mididevice.h @@ -34,6 +34,43 @@ #define MAX_MIDI_MESSAGE MAX_DX7_SYSEX_LENGTH class CMiniDexed; +class CMIDIDevice; + +struct TMIDIRoute +{ + ~TMIDIRoute (); + + enum TRouteOP + { + P2 = 0x82, + LtCenter = 0x90, + GtCenter = 0x91, + Betw00n07 = 0x92, + Betw08n15 = 0x93, + Betw16n23 = 0x94 + }; + + u8 ucSCable; + u8 ucSCh; + u8 ucSType; + u8 ucSP1; + u8 ucSP2; + u8 ucDCh; + u8 ucDType; + u8 ucDP1; + u8 ucDP2; + u8 ucTimerTarget; + unsigned usTimerExpire; + TKernelTimerHandle hTimer; + bool bSkip; + bool bToggle; + bool bGroup; + bool bGroupHead; + bool bGroupActive; + bool bGroupHold; // hold flag for GroupHeads, or set hold the group +}; + +void GetRoutedMIDI (TMIDIRoute *pRouteMap, CMIDIDevice *pDevice, u8 *pCable, u8 *pChannel, u8 *pType, u8 *pP1, u8 *pP2, bool *bSkip); class CMIDIDevice { @@ -53,16 +90,22 @@ class CMIDIDevice void SetChannel (u8 ucChannel, unsigned nTG); u8 GetChannel (unsigned nTG) const; + void SetRouteMap (TMIDIRoute *pRouteMap); + virtual void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) {} // Change signature to specify device name void SendSystemExclusiveVoice(uint8_t nVoice, const std::string& deviceName, unsigned nCable, uint8_t nTG); const std::string& GetDeviceName() const { return m_DeviceName; } + static void s_HandleTimerTimeout(TKernelTimerHandle hTimer, void *pParam, void *pContext); + protected: void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); void AddDevice (const char *pDeviceName); void HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG); + virtual void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2); + private: bool HandleMIDISystemCC(const u8 ucCC, const u8 ucCCval); @@ -82,6 +125,8 @@ class CMIDIDevice std::string m_DeviceName; + TMIDIRoute *m_pRouteMap; + typedef std::unordered_map TDeviceMap; static TDeviceMap s_DeviceMap; diff --git a/src/midikeyboard.cpp b/src/midikeyboard.cpp index db71168d1..274741896 100644 --- a/src/midikeyboard.cpp +++ b/src/midikeyboard.cpp @@ -25,19 +25,26 @@ #include #include +#define DISPLAY_REFRESH_RATE_US 25000 + CMIDIKeyboard::CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserInterface *pUI, unsigned nInstance) : CMIDIDevice (pSynthesizer, pConfig, pUI), m_nSysExIdx (0), m_nInstance (nInstance), - m_pMIDIDevice (0) + m_pMIDIDevice (0), + m_pDAWController (0) { m_DeviceName.Format ("umidi%u", nInstance+1); AddDevice (m_DeviceName); + + if (pConfig->GetDAWControllerEnabled ()) + m_pDAWController = new CDAWController (pSynthesizer, this, pConfig, pUI); } CMIDIKeyboard::~CMIDIKeyboard (void) { + delete m_pDAWController; } void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) @@ -55,6 +62,15 @@ void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) delete [] Entry.pMessage; } + unsigned time = CTimer::GetClockTicks (); + unsigned diff = time - m_LastDisplayRefreshTime; + if (m_LastDisplayEntry.nLength && diff > DISPLAY_REFRESH_RATE_US) + { + m_pMIDIDevice->SendPlainMIDI (m_LastDisplayEntry.nCable, m_LastDisplayEntry.pMessage, m_LastDisplayEntry.nLength); + m_LastDisplayEntry.nLength = 0; + m_LastDisplayRefreshTime = time; + } + if (!bPlugAndPlayUpdated) { return; @@ -69,6 +85,9 @@ void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) m_pMIDIDevice->RegisterPacketHandler (MIDIPacketHandler, this); m_pMIDIDevice->RegisterRemovedHandler (DeviceRemovedHandler, this); + + if (m_pDAWController) + m_pDAWController->OnConnect(); } } } @@ -85,6 +104,15 @@ void CMIDIKeyboard::Send (const u8 *pMessage, size_t nLength, unsigned nCable) m_SendQueue.push (Entry); } +void CMIDIKeyboard::SendDisplay (const u8 *pMessage, size_t nLength, unsigned nCable) +{ + assert (nLength <= sizeof m_LastMessage); + + m_LastDisplayEntry.nLength = nLength; + m_LastDisplayEntry.nCable = nCable; + memcpy (m_LastMessage, pMessage, nLength); +} + // Most packets will be passed straight onto the main MIDI message handler // but SysEx messages are multiple USB packets and so will need building up // before parsing. @@ -122,6 +150,10 @@ void CMIDIKeyboard::USBMIDIMessageHandler (u8 *pPacket, unsigned nLength, unsign m_SysEx[m_nSysExIdx++] = pPacket[i]; //printf ("SysEx End Idx=%d\n", m_nSysExIdx); MIDIMessageHandler (m_SysEx, m_nSysExIdx, nCable); + + if (m_pDAWController) + m_pDAWController->MIDISysexHandler (m_SysEx, m_nSysExIdx, nCable); + // Reset ready for next time m_nSysExIdx = 0; } @@ -160,3 +192,28 @@ void CMIDIKeyboard::DeviceRemovedHandler (CDevice *pDevice, void *pContext) pThis->m_pMIDIDevice = 0; } + +void CMIDIKeyboard::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + if (m_pMIDIDevice && m_pDAWController) + m_pDAWController->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); +} + +void CMIDIKeyboard::UpdateDAWState (void) +{ + if (m_pMIDIDevice && m_pDAWController) + m_pDAWController->UpdateState (); +} + +void CMIDIKeyboard::UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + if (m_pMIDIDevice && m_pDAWController) + m_pDAWController->UpdateMenu (Type, ucPage, ucOP, ucTG); +} + +void CMIDIKeyboard::MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) +{ + if (m_pDAWController) + m_pDAWController->MIDIListener (ucCable, ucChannel, ucType, ucP1, ucP2); +} diff --git a/src/midikeyboard.h b/src/midikeyboard.h index bf6268903..ae49a3d77 100644 --- a/src/midikeyboard.h +++ b/src/midikeyboard.h @@ -25,6 +25,7 @@ #include "mididevice.h" #include "config.h" +#include "dawcontroller.h" #include #include #include @@ -44,6 +45,13 @@ class CMIDIKeyboard : public CMIDIDevice void Process (boolean bPlugAndPlayUpdated); void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) override; + void SendDisplay (const u8 *pMessage, size_t nLength, unsigned nCable = 0); + + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + + void UpdateDAWState (void); + void UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG); private: static void MIDIPacketHandler (unsigned nCable, u8 *pPacket, unsigned nLength, unsigned nDevice, void *pParam); @@ -51,6 +59,8 @@ class CMIDIKeyboard : public CMIDIDevice void USBMIDIMessageHandler (u8 *pPacket, unsigned nLength, unsigned nCable, unsigned nDevice); + void MIDIListener (u8 ucCable, u8 ucChannel, u8 ucType, u8 ucP1, u8 ucP2) override; + private: struct TSendQueueEntry { @@ -68,6 +78,11 @@ class CMIDIKeyboard : public CMIDIDevice CUSBMIDIDevice * volatile m_pMIDIDevice; std::queue m_SendQueue; + u8 m_LastMessage[256]; + TSendQueueEntry m_LastDisplayEntry = {m_LastMessage, 0, 0}; + unsigned m_LastDisplayRefreshTime = 0; + + CDAWController *m_pDAWController; }; #endif diff --git a/src/midipin.cpp b/src/midipin.cpp index d03d73aa3..4b89e7899 100644 --- a/src/midipin.cpp +++ b/src/midipin.cpp @@ -19,13 +19,12 @@ // #include "midipin.h" #include -#include LOGMODULE ("midipin"); CMIDIPin::CMIDIPin (unsigned nPinNumber) : m_nPinNumber (nPinNumber), - m_nValue (HIGH) + m_nValue (0) { } @@ -40,16 +39,6 @@ unsigned CMIDIPin::Read (void) void CMIDIPin::Write (unsigned nValue) { - // Takes values in the MIDI controller range 0 to 127 - // and OFF < 64 < ON. - // Simulates a PULLUP IO pin, so "true" is LOW (0) - if (nValue >= 64) { - // "on" - m_nValue = LOW; - } else { - // "off" - m_nValue = HIGH; - } - return; + m_nValue = nValue; } diff --git a/src/midipin.h b/src/midipin.h index 7fa3f1dbb..1b1dc8770 100644 --- a/src/midipin.h +++ b/src/midipin.h @@ -32,19 +32,17 @@ #define MidiPinToCC(p) (((p)>=MIDI_PINS)?((p)-MIDI_PINS):0) #define isMidiPin(p) (((p)>=MIDI_PINS)?1:0) +#define MIDIPIN_CENTER 64 + class CMIDIPin { public: CMIDIPin (unsigned nPinNumber); // pinNumber = ccToMidiPin (MIDI CC number) ~CMIDIPin (void); - // Will return MP_HIGH or MP_LOW. - // Should be treated as a PULLED UP IO pin - // i.e. treated as "active low" (LOW) when pressed. + // Will return the value written to unsigned Read (void); - - // MIDI CC values >=64 will set the MIDI pin to LOW ("on") - // MIDI CC values <= 63 will set the MIDI pin to HIGH ("off") + void Write (unsigned nValue); private: diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 257ef55ce..953cb118b 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -26,11 +26,12 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include "arm_float_to_q23.h" #include "arm_scale_zip_f32.h" +#include "arm_zip_f32.h" const char WLANFirmwarePath[] = "SD:firmware/"; const char WLANConfigFile[] = "SD:wpa_supplicant.conf"; @@ -46,20 +47,28 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, CMultiCoreSupport (CMemorySystem::Get ()), #endif m_pConfig (pConfig), + m_pTG {}, m_UI (this, pGPIOManager, pI2CMaster, pSPIMaster, pConfig), m_PerformanceConfig (pFileSystem), + m_pMIDIKeyboard {}, m_PCKeyboard (this, pConfig, &m_UI), m_SerialMIDI (this, pInterrupt, pConfig, &m_UI), + m_fMasterVolume{}, + m_fMasterVolumeW(0), m_bUseSerial (false), m_bQuadDAC8Chan (false), - m_pSoundDevice (0), + m_pSoundDevice (nullptr), m_bChannelsSwapped (pConfig->GetChannelsSwapped ()), #ifdef ARM_ALLOW_MULTI_CORE // m_nActiveTGsLog2 (0), #endif + m_nLastKeyDown{}, m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()), m_bProfileEnabled (m_pConfig->GetProfileEnabled ()), + fx_chain {}, + tg_mixer {}, + sendfx_mixer {}, m_pNet(nullptr), m_pNetDevice(nullptr), m_WLAN(nullptr), @@ -67,6 +76,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bNetworkReady(false), m_bNetworkInit(false), m_UDPMIDI(nullptr), + m_pFTPDaemon(nullptr), m_pmDNSPublisher (nullptr), m_bSavePerformance (false), m_bSavePerformanceNewFile (false), @@ -75,7 +85,10 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_bSetFirstPerformance (false), m_bDeletePerformance (false), m_bLoadPerformanceBusy(false), - m_bLoadPerformanceBankBusy(false) + m_bLoadPerformanceBankBusy(false), + m_bVolRampDownWait{}, + m_bVolRampedDown{}, + m_fRamp{10.0f / pConfig->GetSampleRate()} { assert (m_pConfig); @@ -101,6 +114,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nPortamentoGlissando[i] = 0; m_nPortamentoTime[i] = 0; m_bMonoMode[i]=0; + m_nTGLink[i]=0; m_nNoteLimitLow[i] = 0; m_nNoteLimitHigh[i] = 127; m_nNoteShift[i] = 0; @@ -114,7 +128,25 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, m_nAftertouchRange[i]=99; m_nAftertouchTarget[i]=0; - m_nReverbSend[i] = 0; + m_nFX1Send[i] = 25; + m_nFX2Send[i] = 0; + + m_bCompressorEnable[i] = 0; + m_nCompressorPreGain[i] = 0; + m_nCompressorThresh[i] = -20; + m_nCompressorRatio[i] = 5; + m_nCompressorAttack[i] = 5; + m_nCompressorRelease[i] = 200; + m_nCompressorMakeupGain[i] = 0; + + m_nEQLow[i] = 0; + m_nEQMid[i] = 0; + m_nEQHigh[i] = 0; + m_nEQGain[i] = 0; + m_nEQLowMidFreq[i] = 24; + m_nEQMidHighFreq[i] = 44; + + m_bEnabled[i] = 1; // Active the required number of active TGs if (iGetSampleRate (), pConfig->GetChunkSize ()); - - // The channels are swapped by default in the HDMI sound driver. - // TODO: Remove this line, when this has been fixed in the driver. - m_bChannelsSwapped = !m_bChannelsSwapped; #endif } else @@ -235,26 +263,32 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt, } #endif - float masterVolNorm = (float)(pConfig->GetMasterVolume()) / 127.0f; - setMasterVolume(masterVolNorm); - // BEGIN setup tg_mixer - tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); + tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); // END setup tgmixer - // BEGIN setup reverb - reverb_send_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2); - reverb = new AudioEffectPlateReverb(pConfig->GetSampleRate()); - SetParameter (ParameterReverbEnable, 1); - SetParameter (ParameterReverbSize, 70); - SetParameter (ParameterReverbHighDamp, 50); - SetParameter (ParameterReverbLowDamp, 50); - SetParameter (ParameterReverbLowPass, 30); - SetParameter (ParameterReverbDiffusion, 65); - SetParameter (ParameterReverbLevel, 99); + for (unsigned nFX = 0; nFX < CConfig::FXMixers; nFX++) + { + sendfx_mixer[nFX] = new AudioStereoMixer(pConfig->GetChunkSize()/2, pConfig->GetSampleRate()); + } + + for (unsigned nFX = 0; nFX < CConfig::FXChains; nFX++) + { + fx_chain[nFX] = new AudioFXChain(pConfig->GetSampleRate()); + + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + bool bSaveOnly = p.Flags & FX::FXComposite; + SetFXParameter (FX::TFXParameter(nParam), p.Default, nFX, bSaveOnly); + } + } + // END setup reverb - SetParameter (ParameterCompressorEnable, 1); + SetParameter (ParameterMasterVolume, pConfig->GetMasterVolume()); + SetParameter (ParameterMixerDryLevel, 99); + SetParameter (ParameterFXBypass, 0); SetPerformanceSelectChannel(m_pConfig->GetPerformanceSelectChannel()); @@ -323,8 +357,12 @@ bool CMiniDexed::Initialize (void) tg_mixer->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); tg_mixer->gain(i,1.0f); - reverb_send_mixer->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); - reverb_send_mixer->gain(i,mapfloat(m_nReverbSend[i],0,99,0.0f,1.0f)); + + for (unsigned nFX = 0; nFX < CConfig::FXMixers; ++nFX) + { + sendfx_mixer[nFX]->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f)); + sendfx_mixer[nFX]->gain(i,mapfloat(nFX == 0 ? m_nFX1Send[i] : m_nFX2Send[i],0,99,0.0f,1.0f)); + } } m_PerformanceConfig.Init(m_nToneGenerators); @@ -367,6 +405,8 @@ bool CMiniDexed::Initialize (void) m_pSoundDevice->Start (); + m_UI.LoadDefaultScreen (); + #ifdef ARM_ALLOW_MULTI_CORE // start secondary cores if (!CMultiCoreSupport::Initialize ()) @@ -439,12 +479,24 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) pScheduler->Yield(); } - if (m_bSetNewPerformance && !m_bSetNewPerformanceBank && !m_bLoadPerformanceBusy && !m_bLoadPerformanceBankBusy) + if (m_bSetNewPerformance && m_bVolRampedDown && !m_bSetNewPerformanceBank && !m_bLoadPerformanceBusy && !m_bLoadPerformanceBankBusy) { + for (unsigned i = 0; i < m_nToneGenerators; ++i) + { + m_pTG[i]->resetState(); + } + DoSetNewPerformance (); + + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + fx_chain[nFX]->resetState(); + } + if (m_nSetNewPerformanceID == GetActualPerformanceID()) { m_bSetNewPerformance = false; + m_bVolRampedDown = false; } pScheduler->Yield(); } @@ -461,6 +513,9 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated) m_GetChunkTimer.Dump (); pScheduler->Yield(); } + + m_Status.Update(); + if (m_pNet) { UpdateNetwork(); } @@ -483,13 +538,14 @@ void CMiniDexed::Run (unsigned nCore) { while (m_CoreStatus[nCore] != CoreStatusIdle) { - // just wait + WaitForEvent (); } } while (m_CoreStatus[nCore] != CoreStatusExit) { ProcessSound (); + WaitForEvent (); } } else // core 2 and 3 @@ -497,9 +553,11 @@ void CMiniDexed::Run (unsigned nCore) while (1) { m_CoreStatus[nCore] = CoreStatusIdle; // ready to be kicked + SendIPI (1, IPI_USER); + while (m_CoreStatus[nCore] == CoreStatusIdle) { - // just wait + WaitForEvent (); } // now kicked from core 1 @@ -729,22 +787,42 @@ void CMiniDexed::SetPan (unsigned nPan, unsigned nTG) m_nPan[nTG] = nPan; tg_mixer->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); - reverb_send_mixer->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); + + for (unsigned nFX = 0; nFX < CConfig::FXMixers; ++nFX) + { + sendfx_mixer[nFX]->pan(nTG,mapfloat(nPan,0,127,0.0f,1.0f)); + } m_UI.ParameterChanged (); } -void CMiniDexed::SetReverbSend (unsigned nReverbSend, unsigned nTG) +void CMiniDexed::SetFX1Send (unsigned nFX1Send, unsigned nTG) { - nReverbSend=constrain((int)nReverbSend,0,99); + nFX1Send=constrain((int)nFX1Send,0,99); assert (nTG < CConfig::AllToneGenerators); if (nTG >= m_nToneGenerators) return; // Not an active TG + if (0 >= CConfig::FXMixers) return; - m_nReverbSend[nTG] = nReverbSend; + m_nFX1Send[nTG] = nFX1Send; + + sendfx_mixer[0]->gain(nTG,mapfloat(nFX1Send,0,99,0.0f,1.0f)); + + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetFX2Send (unsigned nFX2Send, unsigned nTG) +{ + nFX2Send=constrain((int)nFX2Send,0,99); + + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + if (1 >= CConfig::FXMixers) return; + + m_nFX2Send[nTG] = nFX2Send; + + sendfx_mixer[1]->gain(nTG,mapfloat(nFX2Send,0,99,0.0f,1.0f)); - reverb_send_mixer->gain(nTG,mapfloat(nReverbSend,0,99,0.0f,1.0f)); - m_UI.ParameterChanged (); } @@ -862,6 +940,8 @@ void CMiniDexed::keydown (int16_t pitch, uint8_t velocity, unsigned nTG) assert (m_pTG[nTG]); + m_nLastKeyDown = pitch; + pitch = ApplyNoteLimits (pitch, nTG); if (pitch >= 0) { @@ -997,76 +1077,361 @@ void CMiniDexed::ControllersRefresh (unsigned nTG) void CMiniDexed::SetParameter (TParameter Parameter, int nValue) { - assert (reverb); - assert (Parameter < ParameterUnknown); + + switch (Parameter) + { + case ParameterPerformanceSelectChannel: + // Nothing more to do + break; + + case ParameterPerformanceBank: + BankSelectPerformance(nValue); + break; + + case ParameterMasterVolume: + nValue=constrain((int)nValue,0,127); + setMasterVolume (nValue / 127.0f); + m_UI.ParameterChanged (); + break; + + case ParameterMixerDryLevel: + nValue = constrain(nValue, 0, 99); + tg_mixer->gain(mapfloat(nValue,0,99,0.0f,1.0f)); + break; + + case ParameterFXBypass: + break; + + default: + assert (0); + break; + } + m_nParameter[Parameter] = nValue; +} + +int CMiniDexed::GetParameter (TParameter Parameter) +{ + assert (Parameter < ParameterUnknown); + return m_nParameter[Parameter]; +} + +void CMiniDexed::SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX, bool bSaveOnly) +{ + assert (nFX < CConfig::FXChains); + assert (Parameter < FX::FXParameterUnknown); + + const FX::FXParameterType &p = FX::s_FXParameter[Parameter]; + nValue = constrain((int)nValue, p.Minimum, p.Maximum); + + m_nFXParameter[nFX][Parameter] = nValue; + + if (bSaveOnly) return; switch (Parameter) { - case ParameterCompressorEnable: - for (unsigned nTG = 0; nTG < m_nToneGenerators; nTG++) + case FX::FXParameterSlot0: + case FX::FXParameterSlot1: + case FX::FXParameterSlot2: + fx_chain[nFX]->setSlot(Parameter - FX::FXParameterSlot0, nValue); + break; + + case FX::FXParameterYKChorusMix: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setMix (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusEnable1: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus1 (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusEnable2: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus2 (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusLFORate1: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus1LFORate (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusLFORate2: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->yk_chorus.setChorus2LFORate (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterYKChorusBypass: + fx_chain[nFX]->yk_chorus.bypass = nValue; + break; + + case FX::FXParameterDreamDelayMix: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setMix (nValue / 100.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayMode: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setMode ((AudioEffectDreamDelay::Mode)nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayTime: + SetFXParameter (FX::FXParameterDreamDelayTimeL, nValue, nFX); + SetFXParameter (FX::FXParameterDreamDelayTimeR, nValue, nFX); + break; + + case FX::FXParameterDreamDelayTimeL: + m_FXSpinLock.Acquire (); + + if (nValue <= 100) + { + fx_chain[nFX]->dream_delay.setTimeL (nValue / 100.f); + fx_chain[nFX]->dream_delay.setTimeLSync (AudioEffectDreamDelay::SYNC_NONE); + } + else + { + fx_chain[nFX]->dream_delay.setTimeLSync ((AudioEffectDreamDelay::Sync)(nValue - 100)); + } + + m_FXSpinLock.Release (); + break; + + case FX::FXParameterDreamDelayTimeR: + m_FXSpinLock.Acquire (); + + if (nValue <= 100) + { + fx_chain[nFX]->dream_delay.setTimeR (nValue / 100.f); + fx_chain[nFX]->dream_delay.setTimeRSync (AudioEffectDreamDelay::SYNC_NONE); + } + else { - assert (m_pTG[nTG]); - m_pTG[nTG]->setCompressor (!!nValue); + fx_chain[nFX]->dream_delay.setTimeRSync ((AudioEffectDreamDelay::Sync)(nValue - 100)); } + + m_FXSpinLock.Release (); break; - case ParameterReverbEnable: - nValue=constrain((int)nValue,0,1); - m_ReverbSpinLock.Acquire (); - reverb->set_bypass (!nValue); - m_ReverbSpinLock.Release (); + case FX::FXParameterDreamDelayTempo: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setTempo (nValue); + m_FXSpinLock.Release (); break; - case ParameterReverbSize: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->size (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterDreamDelayFeedback: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setFeedback (nValue / 100.0f); + m_FXSpinLock.Release (); break; - case ParameterReverbHighDamp: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->hidamp (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterDreamDelayHighCut: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->dream_delay.setHighCut (MIDI_EQ_HZ[nValue]); + m_FXSpinLock.Release (); break; - case ParameterReverbLowDamp: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->lodamp (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterDreamDelayBypass: + fx_chain[nFX]->dream_delay.bypass = nValue; break; - case ParameterReverbLowPass: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->lowpass (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterPlateReverbMix: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.set_mix (nValue / 100.0f); + m_FXSpinLock.Release (); break; - case ParameterReverbDiffusion: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->diffusion (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterPlateReverbSize: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.size (nValue / 99.0f); + m_FXSpinLock.Release (); break; - case ParameterReverbLevel: - nValue=constrain((int)nValue,0,99); - m_ReverbSpinLock.Acquire (); - reverb->level (nValue / 99.0f); - m_ReverbSpinLock.Release (); + case FX::FXParameterPlateReverbHighDamp: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.hidamp (nValue / 99.0f); + m_FXSpinLock.Release (); break; - case ParameterPerformanceSelectChannel: - // Nothing more to do + case FX::FXParameterPlateReverbLowDamp: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.lodamp (nValue / 99.0f); + m_FXSpinLock.Release (); break; - case ParameterPerformanceBank: - BankSelectPerformance(nValue); + case FX::FXParameterPlateReverbLowPass: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.lowpass (nValue / 99.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterPlateReverbDiffusion: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->plate_reverb.diffusion (nValue / 99.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterPlateReverbBypass: + fx_chain[nFX]->plate_reverb.bypass = nValue; + break; + + case FX::FXParameterCloudSeed2Preset: + fx_chain[nFX]->cloudseed2.loadPreset (nValue); + break; + + case FX::FXParameterCloudSeed2Interpolation: + case FX::FXParameterCloudSeed2LowCutEnabled: + case FX::FXParameterCloudSeed2HighCutEnabled: + case FX::FXParameterCloudSeed2InputMix: + case FX::FXParameterCloudSeed2LowCut: + case FX::FXParameterCloudSeed2HighCut: + case FX::FXParameterCloudSeed2DryOut: + case FX::FXParameterCloudSeed2EarlyOut: + case FX::FXParameterCloudSeed2LateOut: + case FX::FXParameterCloudSeed2TapEnabled: + case FX::FXParameterCloudSeed2TapCount: + case FX::FXParameterCloudSeed2TapDecay: + case FX::FXParameterCloudSeed2TapPredelay: + case FX::FXParameterCloudSeed2TapLength: + case FX::FXParameterCloudSeed2EarlyDiffuseEnabled: + case FX::FXParameterCloudSeed2EarlyDiffuseCount: + case FX::FXParameterCloudSeed2EarlyDiffuseDelay: + case FX::FXParameterCloudSeed2EarlyDiffuseModAmount: + case FX::FXParameterCloudSeed2EarlyDiffuseFeedback: + case FX::FXParameterCloudSeed2EarlyDiffuseModRate: + case FX::FXParameterCloudSeed2LateMode: + case FX::FXParameterCloudSeed2LateLineCount: + case FX::FXParameterCloudSeed2LateDiffuseEnabled: + case FX::FXParameterCloudSeed2LateDiffuseCount: + case FX::FXParameterCloudSeed2LateLineSize: + case FX::FXParameterCloudSeed2LateLineModAmount: + case FX::FXParameterCloudSeed2LateDiffuseDelay: + case FX::FXParameterCloudSeed2LateDiffuseModAmount: + case FX::FXParameterCloudSeed2LateLineDecay: + case FX::FXParameterCloudSeed2LateLineModRate: + case FX::FXParameterCloudSeed2LateDiffuseFeedback: + case FX::FXParameterCloudSeed2LateDiffuseModRate: + case FX::FXParameterCloudSeed2EqLowShelfEnabled: + case FX::FXParameterCloudSeed2EqHighShelfEnabled: + case FX::FXParameterCloudSeed2EqLowpassEnabled: + case FX::FXParameterCloudSeed2EqLowFreq: + case FX::FXParameterCloudSeed2EqHighFreq: + case FX::FXParameterCloudSeed2EqCutoff: + case FX::FXParameterCloudSeed2EqLowGain: + case FX::FXParameterCloudSeed2EqHighGain: + case FX::FXParameterCloudSeed2EqCrossSeed: + case FX::FXParameterCloudSeed2SeedTap: + case FX::FXParameterCloudSeed2SeedDiffusion: + case FX::FXParameterCloudSeed2SeedDelay: + case FX::FXParameterCloudSeed2SeedPostDiffusion: + fx_chain[nFX]->cloudseed2.setParameter (Parameter - FX::FXParameterCloudSeed2Interpolation, mapfloat(nValue, p.Minimum, p.Maximum, 0.0f, 1.0f)); + break; + + case FX::FXParameterCloudSeed2Bypass: + fx_chain[nFX]->cloudseed2.bypass = nValue; + break; + + case FX::FXParameterCompressorPreGain: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setPreGain_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorThresh: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setThresh_dBFS (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorRatio: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setCompressionRatio (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorAttack: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setAttack_sec ((nValue ?: 1) / 1000.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorRelease: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setRelease_sec ((nValue ?: 1) / 1000.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorMakeupGain: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.setMakeupGain_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorHPFilterEnable: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->compressor.enableHPFilter (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterCompressorBypass: + fx_chain[nFX]->compressor.bypass = nValue; + break; + + case FX::FXParameterEQLow: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setLow_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQMid: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setMid_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQHigh: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setHigh_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQGain: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->eq.setGain_dB (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQLowMidFreq: + m_FXSpinLock.Acquire (); + m_nFXParameter[nFX][Parameter] = fx_chain[nFX]->eq.setLowMidFreq_n (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQMidHighFreq: + m_FXSpinLock.Acquire (); + m_nFXParameter[nFX][Parameter] = fx_chain[nFX]->eq.setMidHighFreq_n (nValue); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterEQBypass: + fx_chain[nFX]->eq.bypass = nValue; + break; + + case FX::FXParameterReturnLevel: + m_FXSpinLock.Acquire (); + fx_chain[nFX]->set_level (nValue / 99.0f); + m_FXSpinLock.Release (); + break; + + case FX::FXParameterBypass: + fx_chain[nFX]->bypass = nValue; break; default: @@ -1075,66 +1440,114 @@ void CMiniDexed::SetParameter (TParameter Parameter, int nValue) } } -int CMiniDexed::GetParameter (TParameter Parameter) +int CMiniDexed::GetFXParameter (FX::TFXParameter Parameter, unsigned nFX) { - assert (Parameter < ParameterUnknown); - return m_nParameter[Parameter]; + assert (nFX < CConfig::FXChains); + assert (Parameter < FX::FXParameterUnknown); + + if (Parameter >= FX::FXParameterCloudSeed2Interpolation && Parameter <= FX::FXParameterCloudSeed2SeedPostDiffusion) + { + const FX::FXParameterType &p = FX::s_FXParameter[Parameter]; + return mapfloat(fx_chain[nFX]->cloudseed2.getParameter (Parameter - FX::FXParameterCloudSeed2Interpolation), 0.0f, 1.0f, p.Minimum, p.Maximum); + } + + return m_nFXParameter[nFX][Parameter]; } void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG - switch (Parameter) + unsigned nTGLink = m_nTGLink[nTG]; + + for (unsigned i = 0; i < m_nToneGenerators; i++) { - case TGParameterVoiceBank: BankSelect (nValue, nTG); break; - case TGParameterVoiceBankMSB: BankSelectMSB (nValue, nTG); break; - case TGParameterVoiceBankLSB: BankSelectLSB (nValue, nTG); break; - case TGParameterProgram: ProgramChange (nValue, nTG); break; - case TGParameterVolume: SetVolume (nValue, nTG); break; - case TGParameterPan: SetPan (nValue, nTG); break; - case TGParameterMasterTune: SetMasterTune (nValue, nTG); break; - case TGParameterCutoff: SetCutoff (nValue, nTG); break; - case TGParameterResonance: SetResonance (nValue, nTG); break; - case TGParameterPitchBendRange: setPitchbendRange (nValue, nTG); break; - case TGParameterPitchBendStep: setPitchbendStep (nValue, nTG); break; - case TGParameterPortamentoMode: setPortamentoMode (nValue, nTG); break; - case TGParameterPortamentoGlissando: setPortamentoGlissando (nValue, nTG); break; - case TGParameterPortamentoTime: setPortamentoTime (nValue, nTG); break; - case TGParameterMonoMode: setMonoMode (nValue , nTG); break; - - case TGParameterMWRange: setModController(0, 0, nValue, nTG); break; - case TGParameterMWPitch: setModController(0, 1, nValue, nTG); break; - case TGParameterMWAmplitude: setModController(0, 2, nValue, nTG); break; - case TGParameterMWEGBias: setModController(0, 3, nValue, nTG); break; - - case TGParameterFCRange: setModController(1, 0, nValue, nTG); break; - case TGParameterFCPitch: setModController(1, 1, nValue, nTG); break; - case TGParameterFCAmplitude: setModController(1, 2, nValue, nTG); break; - case TGParameterFCEGBias: setModController(1, 3, nValue, nTG); break; - - case TGParameterBCRange: setModController(2, 0, nValue, nTG); break; - case TGParameterBCPitch: setModController(2, 1, nValue, nTG); break; - case TGParameterBCAmplitude: setModController(2, 2, nValue, nTG); break; - case TGParameterBCEGBias: setModController(2, 3, nValue, nTG); break; - - case TGParameterATRange: setModController(3, 0, nValue, nTG); break; - case TGParameterATPitch: setModController(3, 1, nValue, nTG); break; - case TGParameterATAmplitude: setModController(3, 2, nValue, nTG); break; - case TGParameterATEGBias: setModController(3, 3, nValue, nTG); break; - - - case TGParameterMIDIChannel: - assert (0 <= nValue && nValue <= 255); - SetMIDIChannel ((uint8_t) nValue, nTG); - break; + if (i != nTG && (!nTGLink || m_nTGLink[i] != nTGLink)) + continue; - case TGParameterReverbSend: SetReverbSend (nValue, nTG); break; + if (i != nTG && Parameter == TGParameterTGLink) + continue; - default: - assert (0); - break; + if (i != nTG && Parameter == TGParameterPan) + continue; + + if (i != nTG && Parameter == TGParameterMasterTune) + continue; + + switch (Parameter) + { + case TGParameterVoiceBank: BankSelect (nValue, i); break; + case TGParameterVoiceBankMSB: BankSelectMSB (nValue, i); break; + case TGParameterVoiceBankLSB: BankSelectLSB (nValue, i); break; + case TGParameterProgram: ProgramChange (nValue, i); break; + case TGParameterVolume: SetVolume (nValue, i); break; + case TGParameterPan: SetPan (nValue, i); break; + case TGParameterMasterTune: SetMasterTune (nValue, i); break; + case TGParameterCutoff: SetCutoff (nValue, i); break; + case TGParameterResonance: SetResonance (nValue, i); break; + case TGParameterPitchBendRange: setPitchbendRange (nValue, i); break; + case TGParameterPitchBendStep: setPitchbendStep (nValue, i); break; + case TGParameterPortamentoMode: setPortamentoMode (nValue, i); break; + case TGParameterPortamentoGlissando: setPortamentoGlissando (nValue, i); break; + case TGParameterPortamentoTime: setPortamentoTime (nValue, i); break; + case TGParameterNoteLimitLow: setNoteLimitLow (nValue, i); break; + case TGParameterNoteLimitHigh: setNoteLimitHigh (nValue, i); break; + case TGParameterNoteShift: setNoteShift (nValue, i); break; + case TGParameterMonoMode: setMonoMode (nValue , i); break; + case TGParameterTGLink: setTGLink(nValue, i); break; + + case TGParameterEnabled: setEnabled (nValue, i); break; + + case TGParameterMWRange: setModController(0, 0, nValue, i); break; + case TGParameterMWPitch: setModController(0, 1, nValue, i); break; + case TGParameterMWAmplitude: setModController(0, 2, nValue, i); break; + case TGParameterMWEGBias: setModController(0, 3, nValue, i); break; + + case TGParameterFCRange: setModController(1, 0, nValue, i); break; + case TGParameterFCPitch: setModController(1, 1, nValue, i); break; + case TGParameterFCAmplitude: setModController(1, 2, nValue, i); break; + case TGParameterFCEGBias: setModController(1, 3, nValue, i); break; + + case TGParameterBCRange: setModController(2, 0, nValue, i); break; + case TGParameterBCPitch: setModController(2, 1, nValue, i); break; + case TGParameterBCAmplitude: setModController(2, 2, nValue, i); break; + case TGParameterBCEGBias: setModController(2, 3, nValue, i); break; + + case TGParameterATRange: setModController(3, 0, nValue, i); break; + case TGParameterATPitch: setModController(3, 1, nValue, i); break; + case TGParameterATAmplitude: setModController(3, 2, nValue, i); break; + case TGParameterATEGBias: setModController(3, 3, nValue, i); break; + + + case TGParameterMIDIChannel: + assert (0 <= nValue && nValue <= 255); + SetMIDIChannel ((uint8_t) nValue, i); + break; + + case TGParameterFX1Send: SetFX1Send (nValue, i); break; + case TGParameterFX2Send: SetFX2Send (nValue, i); break; + + case TGParameterCompressorEnable: SetCompressorEnable (nValue, i); break; + case TGParameterCompressorPreGain: SetCompressorPreGain (nValue, i); break; + case TGParameterCompressorThresh: SetCompressorThresh (nValue, i); break; + case TGParameterCompressorRatio: SetCompressorRatio (nValue, i); break; + case TGParameterCompressorAttack: SetCompressorAttack (nValue, i); break; + case TGParameterCompressorRelease: SetCompressorRelease (nValue, i); break; + case TGParameterCompressorMakeupGain: SetCompressorMakeupGain (nValue, i); break; + + case TGParameterEQLow: SetEQLow (nValue, i); break; + case TGParameterEQMid: SetEQMid (nValue, i); break; + case TGParameterEQHigh: SetEQHigh (nValue, i); break; + case TGParameterEQGain: SetEQGain (nValue, i); break; + case TGParameterEQLowMidFreq: SetEQLowMidFreq (nValue, i); break; + case TGParameterEQMidHighFreq: SetEQMidHighFreq (nValue, i); break; + + default: + assert (0); + break; + } } } @@ -1154,13 +1567,19 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterCutoff: return m_nCutoff[nTG]; case TGParameterResonance: return m_nResonance[nTG]; case TGParameterMIDIChannel: return m_nMIDIChannel[nTG]; - case TGParameterReverbSend: return m_nReverbSend[nTG]; + case TGParameterFX1Send: return m_nFX1Send[nTG]; + case TGParameterFX2Send: return m_nFX2Send[nTG]; case TGParameterPitchBendRange: return m_nPitchBendRange[nTG]; case TGParameterPitchBendStep: return m_nPitchBendStep[nTG]; case TGParameterPortamentoMode: return m_nPortamentoMode[nTG]; case TGParameterPortamentoGlissando: return m_nPortamentoGlissando[nTG]; case TGParameterPortamentoTime: return m_nPortamentoTime[nTG]; + case TGParameterNoteLimitLow: return m_nNoteLimitLow[nTG]; + case TGParameterNoteLimitHigh: return m_nNoteLimitHigh[nTG]; + case TGParameterNoteShift: return m_nNoteShift[nTG]; case TGParameterMonoMode: return m_bMonoMode[nTG] ? 1 : 0; + case TGParameterTGLink: return m_nTGLink[nTG]; + case TGParameterEnabled: return m_bEnabled[nTG] ? 1 : 0; case TGParameterMWRange: return getModController(0, 0, nTG); case TGParameterMWPitch: return getModController(0, 1, nTG); @@ -1182,7 +1601,21 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG) case TGParameterATAmplitude: return getModController(3, 2, nTG); case TGParameterATEGBias: return getModController(3, 3, nTG); - + case TGParameterCompressorEnable: return m_bCompressorEnable[nTG]; + case TGParameterCompressorPreGain: return m_nCompressorPreGain[nTG]; + case TGParameterCompressorThresh: return m_nCompressorThresh[nTG]; + case TGParameterCompressorRatio: return m_nCompressorRatio[nTG]; + case TGParameterCompressorAttack: return m_nCompressorAttack[nTG]; + case TGParameterCompressorRelease: return m_nCompressorRelease[nTG]; + case TGParameterCompressorMakeupGain: return m_nCompressorMakeupGain[nTG]; + + case TGParameterEQLow: return m_nEQLow[nTG]; break; + case TGParameterEQMid: return m_nEQMid[nTG]; break; + case TGParameterEQHigh: return m_nEQHigh[nTG]; break; + case TGParameterEQGain: return m_nEQGain[nTG]; break; + case TGParameterEQLowMidFreq: return m_nEQLowMidFreq[nTG]; break; + case TGParameterEQMidHighFreq: return m_nEQMidHighFreq[nTG]; break; + default: assert (0); return 0; @@ -1200,27 +1633,39 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne if (nOP < 6) { nOP = 5 - nOP; // OPs are in reverse order + } - if (uchOffset == DEXED_OP_ENABLE) + unsigned nTGLink = m_nTGLink[nTG]; + + for (unsigned i = 0; i < m_nToneGenerators; i++) + { + if (i != nTG && (!nTGLink || m_nTGLink[i] != nTGLink)) + continue; + + if (nOP < 6) { - if (uchValue) + if (uchOffset == DEXED_OP_ENABLE) { - setOPMask(m_uchOPMask[nTG] | 1 << nOP, nTG); - } - else - { - setOPMask(m_uchOPMask[nTG] & ~(1 << nOP), nTG); - } + if (uchValue) + { + setOPMask(m_uchOPMask[i] | 1 << nOP, i); + } + else + { + setOPMask(m_uchOPMask[i] & ~(1 << nOP), i); + } - return; - } - } + continue; + } + } - uchOffset += nOP * 21; - assert (uchOffset < 156); + uint8_t offset = uchOffset + nOP * 21; + assert (offset < 156); - m_pTG[nTG]->setVoiceDataElement (uchOffset, uchValue); + m_pTG[i]->setVoiceDataElement (offset, uchValue); + } + m_UI.ParameterChanged (); } uint8_t CMiniDexed::GetVoiceParameter (uint8_t uchOffset, unsigned nOP, unsigned nTG) @@ -1322,6 +1767,7 @@ void CMiniDexed::ProcessSound (void) { assert (m_CoreStatus[nCore] == CoreStatusIdle); m_CoreStatus[nCore] = CoreStatusBusy; + SendIPI (nCore, IPI_USER); } // process the TGs assigned to core 1 @@ -1337,7 +1783,7 @@ void CMiniDexed::ProcessSound (void) { while (m_CoreStatus[nCore] != CoreStatusIdle) { - // just wait + WaitForEvent (); } } @@ -1363,7 +1809,7 @@ void CMiniDexed::ProcessSound (void) // no additional processing. for (uint8_t tg = 0; tg < Channels; tg++) { - tmp_float[(i*Channels)+tg]=m_OutputLevel[tg][i] * nMasterVolume; + tmp_float[(i*Channels)+tg]=m_OutputLevel[tg][i] * m_fMasterVolumeW; } } @@ -1404,35 +1850,39 @@ void CMiniDexed::ProcessSound (void) } // END TG mixing - // BEGIN adding reverb - if (m_nParameter[ParameterReverbEnable]) - { - float32_t ReverbBuffer[2][nFrames]; + // BEGIN adding sendFX + float32_t *FXSendBuffer[2]; - float32_t *ReverbSendBuffer[2]; - reverb_send_mixer->getBuffers(ReverbSendBuffer); + for (unsigned nFX = 0; nFX < CConfig::FXMixers; ++nFX) + { + if (fx_chain[nFX]->get_level() == 0.0f) continue; - reverb_send_mixer->zeroFill(); + sendfx_mixer[nFX]->getBuffers(FXSendBuffer); + sendfx_mixer[nFX]->zeroFill(); for (uint8_t i = 0; i < m_nToneGenerators; i++) { - reverb_send_mixer->doAddMix(i,m_OutputLevel[i]); + sendfx_mixer[nFX]->doAddMix(i,m_OutputLevel[i]); } - m_ReverbSpinLock.Acquire (); - - reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames); + if (!m_nParameter[ParameterFXBypass]) + { + m_FXSpinLock.Acquire (); + fx_chain[nFX]->process(FXSendBuffer[0], FXSendBuffer[1], nFrames); + m_FXSpinLock.Release (); + } - // scale down and add left reverb buffer by reverb level - arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames); - arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames); - // scale down and add right reverb buffer by reverb level - arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames); - arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames); + arm_add_f32(SampleBuffer[0], FXSendBuffer[0], SampleBuffer[0], nFrames); + arm_add_f32(SampleBuffer[1], FXSendBuffer[1], SampleBuffer[1], nFrames); + } + // END adding sendFX - m_ReverbSpinLock.Release (); + if (!m_nParameter[ParameterFXBypass]) + { + m_FXSpinLock.Acquire (); + fx_chain[CConfig::MasterFX]->process(SampleBuffer[0], SampleBuffer[1], nFrames); + m_FXSpinLock.Release (); } - // END adding reverb // swap stereo channels if needed prior to writing back out if (m_bChannelsSwapped) @@ -1441,8 +1891,35 @@ void CMiniDexed::ProcessSound (void) indexR=0; } - // Convert dual float array (left, right) to single int16 array (left/right) - arm_scale_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], nMasterVolume, tmp_float, nFrames); + // Convert dual float array (left, right) to single int32 (q23) array (left/right) + if (m_bVolRampDownWait) + { + float targetVol = 0.0f; + + scale_ramp_f32(SampleBuffer[0], &m_fMasterVolume[0], targetVol, m_fRamp, SampleBuffer[0], nFrames); + scale_ramp_f32(SampleBuffer[1], &m_fMasterVolume[1], targetVol, m_fRamp, SampleBuffer[1], nFrames); + arm_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], tmp_float, nFrames); + + if (targetVol == m_fMasterVolume[0] && targetVol == m_fMasterVolume[1]) + { + m_bVolRampDownWait = false; + m_bVolRampedDown = true; + } + } + else if (m_bVolRampedDown) + { + arm_scale_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], 0.0f, tmp_float, nFrames); + } + else if (m_fMasterVolume[0] == m_fMasterVolumeW && m_fMasterVolume[1] == m_fMasterVolumeW) + { + arm_scale_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], m_fMasterVolumeW, tmp_float, nFrames); + } + else + { + scale_ramp_f32(SampleBuffer[0], &m_fMasterVolume[0], m_fMasterVolumeW, m_fRamp, SampleBuffer[0], nFrames); + scale_ramp_f32(SampleBuffer[1], &m_fMasterVolume[1], m_fMasterVolumeW, m_fRamp, SampleBuffer[1], nFrames); + arm_zip_f32(SampleBuffer[indexL], SampleBuffer[indexR], tmp_float, nFrames); + } arm_float_to_q23(tmp_float,tmp_int,nFrames*2); @@ -1536,7 +2013,8 @@ bool CMiniDexed::DoSavePerformance (void) } m_PerformanceConfig.SetVoiceDataToTxt (m_nRawVoiceData, nTG); m_PerformanceConfig.SetMonoMode (m_bMonoMode[nTG], nTG); - + m_PerformanceConfig.SetTGLink (m_nTGLink[nTG], nTG); + m_PerformanceConfig.SetModulationWheelRange (m_nModulationWheelRange[nTG], nTG); m_PerformanceConfig.SetModulationWheelTarget (m_nModulationWheelTarget[nTG], nTG); m_PerformanceConfig.SetFootControlRange (m_nFootControlRange[nTG], nTG); @@ -1546,17 +2024,36 @@ bool CMiniDexed::DoSavePerformance (void) m_PerformanceConfig.SetAftertouchRange (m_nAftertouchRange[nTG], nTG); m_PerformanceConfig.SetAftertouchTarget (m_nAftertouchTarget[nTG], nTG); - m_PerformanceConfig.SetReverbSend (m_nReverbSend[nTG], nTG); + m_PerformanceConfig.SetFX1Send (m_nFX1Send[nTG], nTG); + m_PerformanceConfig.SetFX2Send (m_nFX2Send[nTG], nTG); + + m_PerformanceConfig.SetCompressorEnable (m_bCompressorEnable[nTG], nTG); + m_PerformanceConfig.SetCompressorPreGain (m_nCompressorPreGain[nTG], nTG); + m_PerformanceConfig.SetCompressorThresh (m_nCompressorThresh[nTG], nTG); + m_PerformanceConfig.SetCompressorRatio (m_nCompressorRatio[nTG], nTG); + m_PerformanceConfig.SetCompressorAttack (m_nCompressorAttack[nTG], nTG); + m_PerformanceConfig.SetCompressorRelease (m_nCompressorRelease[nTG], nTG); + m_PerformanceConfig.SetCompressorMakeupGain (m_nCompressorMakeupGain[nTG], nTG); + + m_PerformanceConfig.SetEQLow (m_nEQLow[nTG], nTG); + m_PerformanceConfig.SetEQMid (m_nEQMid[nTG], nTG); + m_PerformanceConfig.SetEQHigh (m_nEQHigh[nTG], nTG); + m_PerformanceConfig.SetEQGain (m_nEQGain[nTG], nTG); + m_PerformanceConfig.SetEQLowMidFreq (m_nEQLowMidFreq[nTG], nTG); + m_PerformanceConfig.SetEQMidHighFreq (m_nEQMidHighFreq[nTG], nTG); } - m_PerformanceConfig.SetCompressorEnable (!!m_nParameter[ParameterCompressorEnable]); - m_PerformanceConfig.SetReverbEnable (!!m_nParameter[ParameterReverbEnable]); - m_PerformanceConfig.SetReverbSize (m_nParameter[ParameterReverbSize]); - m_PerformanceConfig.SetReverbHighDamp (m_nParameter[ParameterReverbHighDamp]); - m_PerformanceConfig.SetReverbLowDamp (m_nParameter[ParameterReverbLowDamp]); - m_PerformanceConfig.SetReverbLowPass (m_nParameter[ParameterReverbLowPass]); - m_PerformanceConfig.SetReverbDiffusion (m_nParameter[ParameterReverbDiffusion]); - m_PerformanceConfig.SetReverbLevel (m_nParameter[ParameterReverbLevel]); + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + FX::TFXParameter param = FX::TFXParameter (nParam); + m_PerformanceConfig.SetFXParameter (param, GetFXParameter (param, nFX), nFX); + } + } + + m_PerformanceConfig.SetMixerDryLevel (m_nParameter[ParameterMixerDryLevel]); + m_PerformanceConfig.SetFXBypass (m_nParameter[ParameterFXBypass]); if(m_bSaveAsDeault) { @@ -1567,6 +2064,147 @@ bool CMiniDexed::DoSavePerformance (void) return m_PerformanceConfig.Save (); } +void CMiniDexed::SetCompressorEnable(bool compressor, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_bCompressorEnable[nTG] = compressor; + m_pTG[nTG]->setCompressorEnable (compressor); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorPreGain (int preGain, unsigned nTG) +{ + preGain = constrain (preGain, -20, 20); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorPreGain[nTG] = preGain; + m_pTG[nTG]->Compr.setPreGain_dB (preGain); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorThresh (int thresh, unsigned nTG) +{ + thresh = constrain (thresh, -60, 0); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorThresh[nTG] = thresh; + m_pTG[nTG]->Compr.setThresh_dBFS (thresh); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorRatio (unsigned ratio, unsigned nTG) +{ + ratio = constrain (ratio, 1u, CMiniDexed::CompressorRatioInf); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorRatio[nTG] = ratio; + m_pTG[nTG]->Compr.setCompressionRatio (ratio == CompressorRatioInf ? INFINITY : ratio); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorAttack (unsigned attack, unsigned nTG) +{ + attack = constrain (attack, 0u, 1000u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorAttack[nTG] = attack; + m_pTG[nTG]->Compr.setAttack_sec ((attack ?: 1) / 1000.0f, m_pConfig->GetSampleRate ()); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorRelease (unsigned release, unsigned nTG) +{ + release = constrain (release, 0u, 2000u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorRelease[nTG] = release; + m_pTG[nTG]->Compr.setRelease_sec ((release ?: 1) / 1000.0, m_pConfig->GetSampleRate ()); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetCompressorMakeupGain (int makeupGain, unsigned nTG) +{ + makeupGain = constrain (makeupGain, -20, 20); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nCompressorMakeupGain[nTG] = makeupGain; + m_pTG[nTG]->Compr.setMakeupGain_dB (makeupGain); + m_UI.ParameterChanged (); +} + +void CMiniDexed::SetEQLow (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQLow[nTG] = nValue; + m_pTG[nTG]->EQ.setLow_dB(nValue); +} + +void CMiniDexed::SetEQMid (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQMid[nTG] = nValue; + m_pTG[nTG]->EQ.setMid_dB(nValue); +} + +void CMiniDexed::SetEQHigh (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQHigh[nTG] = nValue; + m_pTG[nTG]->EQ.setHigh_dB(nValue); +} + +void CMiniDexed::SetEQGain (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, -24, 24); + m_nEQGain[nTG] = nValue; + m_pTG[nTG]->EQ.setGain_dB(nValue); +} + +void CMiniDexed::SetEQLowMidFreq (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, 0u, 46u); + m_nEQLowMidFreq[nTG] = m_pTG[nTG]->EQ.setLowMidFreq_n(nValue); +} + +void CMiniDexed::SetEQMidHighFreq (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + nValue = constrain(nValue, 28u, 59u); + m_nEQMidHighFreq[nTG] = m_pTG[nTG]->EQ.setMidHighFreq_n(nValue); +} + void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -1579,6 +2217,27 @@ void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG) m_UI.ParameterChanged (); } +void CMiniDexed::setTGLink(uint8_t nTGLink, uint8_t nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + m_nTGLink[nTG]= constrain(nTGLink, 0, 4); + m_UI.ParameterChanged (); +} + +void CMiniDexed::setEnabled (uint8_t enabled, uint8_t nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + assert (m_pTG[nTG]); + + m_bEnabled[nTG] = enabled != 0; + + m_UI.ParameterChanged (); +} + void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG) { range = constrain (range, 0, 12); @@ -1650,6 +2309,51 @@ void CMiniDexed::setPortamentoTime(uint8_t time, uint8_t nTG) m_UI.ParameterChanged (); } +void CMiniDexed::setNoteLimitLow(unsigned limit, uint8_t nTG) +{ + limit = constrain (limit, 0u, 127u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + + m_nNoteLimitLow[nTG] = limit; + + // reset all notes, so they don't stay down + m_pTG[nTG]->deactivate(); + m_UI.ParameterChanged (); +} + +void CMiniDexed::setNoteLimitHigh(unsigned limit, uint8_t nTG) +{ + limit = constrain (limit, 0u, 127u); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + + m_nNoteLimitHigh[nTG] = limit; + + // reset all notes, so they don't stay down + m_pTG[nTG]->deactivate(); + m_UI.ParameterChanged (); +} + +void CMiniDexed::setNoteShift(int shift, uint8_t nTG) +{ + shift = constrain (shift, -24, 24); + assert (nTG < CConfig::AllToneGenerators); + if (nTG >= m_nToneGenerators) return; // Not an active TG + + assert (m_pTG[nTG]); + + m_nNoteShift[nTG] = shift; + + // reset all notes, so they don't stay down + m_pTG[nTG]->deactivate(); + m_UI.ParameterChanged (); +} + void CMiniDexed::setModWheelRange(uint8_t range, uint8_t nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -1846,6 +2550,7 @@ void CMiniDexed::getSysExVoiceDump(uint8_t* dest, uint8_t nTG) void CMiniDexed::setOPMask(uint8_t uchOPMask, uint8_t nTG) { + if (nTG >= m_nToneGenerators) return; // Not an active TG m_uchOPMask[nTG] = uchOPMask; m_pTG[nTG]->setOPAll (m_uchOPMask[nTG]); } @@ -1860,7 +2565,34 @@ void CMiniDexed::setMasterVolume(float32_t vol) // Apply logarithmic scaling to match perceived loudness vol = powf(vol, 2.0f); - nMasterVolume = vol; + m_fMasterVolumeW = vol; +} + +void CMiniDexed::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + m_UI.DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); + + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + m_pMIDIKeyboard[i]->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); + } +} + +void CMiniDexed::UpdateDAWState () +{ + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + m_pMIDIKeyboard[i]->UpdateDAWState (); + } +} + +void CMiniDexed::UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG) +{ + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + m_pMIDIKeyboard[i]->UpdateDAWMenu (Type, ucPage, ucOP, ucTG); + } } std::string CMiniDexed::GetPerformanceFileName(unsigned nID) @@ -1912,6 +2644,8 @@ bool CMiniDexed::SetNewPerformance(unsigned nID) { m_bSetNewPerformance = true; m_nSetNewPerformanceID = nID; + if (!m_bVolRampedDown) + m_bVolRampDownWait = true; return true; } @@ -2000,58 +2734,79 @@ bool CMiniDexed::DoSavePerformanceNewFile (void) void CMiniDexed::LoadPerformanceParameters(void) { for (unsigned nTG = 0; nTG < CConfig::AllToneGenerators; nTG++) + { + BankSelect (m_PerformanceConfig.GetBankNumber (nTG), nTG); + ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG); + SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG); + SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG); + SetPan (m_PerformanceConfig.GetPan (nTG), nTG); + SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG); + SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG); + SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG); + setPitchbendRange (m_PerformanceConfig.GetPitchBendRange (nTG), nTG); + setPitchbendStep (m_PerformanceConfig.GetPitchBendStep (nTG), nTG); + setPortamentoMode (m_PerformanceConfig.GetPortamentoMode (nTG), nTG); + setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG); + setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG); + + setNoteLimitLow(m_PerformanceConfig.GetNoteLimitLow (nTG), nTG); + setNoteLimitHigh(m_PerformanceConfig.GetNoteLimitHigh (nTG), nTG); + setNoteShift(m_PerformanceConfig.GetNoteShift (nTG), nTG); + + if(m_PerformanceConfig.VoiceDataFilled(nTG) && nTG < m_nToneGenerators) { - - BankSelect (m_PerformanceConfig.GetBankNumber (nTG), nTG); - ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG); - SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG); - SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG); - SetPan (m_PerformanceConfig.GetPan (nTG), nTG); - SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG); - SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG); - SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG); - setPitchbendRange (m_PerformanceConfig.GetPitchBendRange (nTG), nTG); - setPitchbendStep (m_PerformanceConfig.GetPitchBendStep (nTG), nTG); - setPortamentoMode (m_PerformanceConfig.GetPortamentoMode (nTG), nTG); - setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG); - setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG); - - m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG); - m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG); - m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG); - - if(m_PerformanceConfig.VoiceDataFilled(nTG)) - { uint8_t* tVoiceData = m_PerformanceConfig.GetVoiceDataFromTxt(nTG); m_pTG[nTG]->loadVoiceParameters(tVoiceData); setOPMask(0b111111, nTG); - } - setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); - SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG); - - setModWheelRange (m_PerformanceConfig.GetModulationWheelRange (nTG), nTG); - setModWheelTarget (m_PerformanceConfig.GetModulationWheelTarget (nTG), nTG); - setFootControllerRange (m_PerformanceConfig.GetFootControlRange (nTG), nTG); - setFootControllerTarget (m_PerformanceConfig.GetFootControlTarget (nTG), nTG); - setBreathControllerRange (m_PerformanceConfig.GetBreathControlRange (nTG), nTG); - setBreathControllerTarget (m_PerformanceConfig.GetBreathControlTarget (nTG), nTG); - setAftertouchRange (m_PerformanceConfig.GetAftertouchRange (nTG), nTG); - setAftertouchTarget (m_PerformanceConfig.GetAftertouchTarget (nTG), nTG); - - } - // Effects - SetParameter (ParameterCompressorEnable, m_PerformanceConfig.GetCompressorEnable () ? 1 : 0); - SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0); - SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ()); - SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ()); - SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ()); - SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ()); - SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ()); - SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ()); + setMonoMode(m_PerformanceConfig.GetMonoMode(nTG) ? 1 : 0, nTG); + setTGLink(m_PerformanceConfig.GetTGLink(nTG), nTG); + setEnabled(1, nTG); + + SetFX1Send (m_PerformanceConfig.GetFX1Send (nTG), nTG); + SetFX2Send (m_PerformanceConfig.GetFX2Send (nTG), nTG); + + setModWheelRange (m_PerformanceConfig.GetModulationWheelRange (nTG), nTG); + setModWheelTarget (m_PerformanceConfig.GetModulationWheelTarget (nTG), nTG); + setFootControllerRange (m_PerformanceConfig.GetFootControlRange (nTG), nTG); + setFootControllerTarget (m_PerformanceConfig.GetFootControlTarget (nTG), nTG); + setBreathControllerRange (m_PerformanceConfig.GetBreathControlRange (nTG), nTG); + setBreathControllerTarget (m_PerformanceConfig.GetBreathControlTarget (nTG), nTG); + setAftertouchRange (m_PerformanceConfig.GetAftertouchRange (nTG), nTG); + setAftertouchTarget (m_PerformanceConfig.GetAftertouchTarget (nTG), nTG); + + SetCompressorEnable (m_PerformanceConfig.GetCompressorEnable (nTG), nTG); + SetCompressorPreGain (m_PerformanceConfig.GetCompressorPreGain (nTG), nTG); + SetCompressorThresh (m_PerformanceConfig.GetCompressorThresh (nTG), nTG); + SetCompressorRatio (m_PerformanceConfig.GetCompressorRatio (nTG), nTG); + SetCompressorAttack (m_PerformanceConfig.GetCompressorAttack (nTG), nTG);; + SetCompressorRelease (m_PerformanceConfig.GetCompressorRelease (nTG), nTG); + SetCompressorMakeupGain (m_PerformanceConfig.GetCompressorMakeupGain (nTG), nTG); + + SetEQLow (m_PerformanceConfig.GetEQLow (nTG), nTG); + SetEQMid (m_PerformanceConfig.GetEQMid (nTG), nTG); + SetEQHigh (m_PerformanceConfig.GetEQHigh (nTG), nTG); + SetEQGain (m_PerformanceConfig.GetEQGain (nTG), nTG); + SetEQLowMidFreq (m_PerformanceConfig.GetEQLowMidFreq (nTG), nTG); + SetEQMidHighFreq (m_PerformanceConfig.GetEQMidHighFreq (nTG), nTG); + } + + for (unsigned nFX=0; nFX < CConfig::FXChains; ++nFX) + { + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + FX::TFXParameter param = FX::TFXParameter(nParam); + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + bool bSaveOnly = p.Flags & FX::FXComposite; + SetFXParameter (param, m_PerformanceConfig.GetFXParameter (param, nFX), nFX, bSaveOnly); + } + } + + SetParameter (ParameterMixerDryLevel, m_PerformanceConfig.GetMixerDryLevel ()); + SetParameter (ParameterFXBypass, m_PerformanceConfig.GetFXBypass ()); - m_UI.DisplayChanged (); + m_UI.DisplayChanged (); } std::string CMiniDexed::GetNewPerformanceDefaultName(void) @@ -2074,6 +2829,11 @@ bool CMiniDexed::IsValidPerformanceBank(unsigned nBankID) return m_PerformanceConfig.IsValidPerformanceBank(nBankID); } +int CMiniDexed::GetLastKeyDown() +{ + return m_nLastKeyDown; +} + void CMiniDexed::SetVoiceName (const std::string &VoiceName, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -2298,8 +3058,6 @@ void CMiniDexed::UpdateNetwork() LOGNOTE("FTP daemon not started (NetworkFTPEnabled=0)"); } - m_UI.DisplayWrite (IPString, "", "TG1", 0, 1); - m_pmDNSPublisher = new CmDNSPublisher (m_pNet); assert (m_pmDNSPublisher); @@ -2319,7 +3077,7 @@ void CMiniDexed::UpdateNetwork() if (m_pConfig->GetSyslogEnabled()) { LOGNOTE ("Syslog server is enabled in configuration"); - CIPAddress ServerIP = m_pConfig->GetNetworkSyslogServerIPAddress(); + const CIPAddress& ServerIP = m_pConfig->GetNetworkSyslogServerIPAddress(); if (ServerIP.IsSet () && !ServerIP.IsNull ()) { static const u16 usServerPort = 8514; @@ -2416,18 +3174,31 @@ bool CMiniDexed::InitNetwork() if (NetDeviceType != NetDeviceTypeUnknown) { - LOGNOTE("CMiniDexed::InitNetwork: Creating CNetSubSystem"); if (m_pConfig->GetNetworkDHCP()) + { + LOGNOTE("CMiniDexed::InitNetwork: Creating CNetSubSystem with DHCP (Hostname: %s)", m_pConfig->GetNetworkHostname()); m_pNet = new CNetSubSystem(0, 0, 0, 0, m_pConfig->GetNetworkHostname(), NetDeviceType); - else + } + else if (m_pConfig->GetNetworkIPAddress().IsSet() && m_pConfig->GetNetworkSubnetMask().IsSet()) + { + CString IPString, SubnetString; + m_pConfig->GetNetworkIPAddress().Format (&IPString); + m_pConfig->GetNetworkSubnetMask().Format (&SubnetString); + LOGNOTE("CMiniDexed::InitNetwork: Creating CNetSubSystem with IP: %s / %s", (const char*)IPString, (const char*)SubnetString); m_pNet = new CNetSubSystem( m_pConfig->GetNetworkIPAddress().Get(), m_pConfig->GetNetworkSubnetMask().Get(), - m_pConfig->GetNetworkDefaultGateway().Get(), - m_pConfig->GetNetworkDNSServer().Get(), + m_pConfig->GetNetworkDefaultGateway().IsSet() ? m_pConfig->GetNetworkDefaultGateway().Get() : 0, + m_pConfig->GetNetworkDNSServer().IsSet() ? m_pConfig->GetNetworkDNSServer().Get() : 0, m_pConfig->GetNetworkHostname(), - NetDeviceType - ); + NetDeviceType); + } + else + { + LOGNOTE ("CMiniDexed::InitNetwork: Neither DHCP nor IP address/subnet mask is set, using DHCP (Hostname: %s)", m_pConfig->GetNetworkHostname()); + m_pNet = new CNetSubSystem(0, 0, 0, 0, m_pConfig->GetNetworkHostname(), NetDeviceType); + } + if (!m_pNet || !m_pNet->Initialize(false)) // Check if m_pNet allocation succeeded { LOGERR("CMiniDexed::InitNetwork: Failed to initialize network subsystem"); @@ -2469,3 +3240,13 @@ bool CMiniDexed::InitNetwork() return false; } } + +const CIPAddress& CMiniDexed::GetNetworkIPAddress() +{ + if (m_pNet) + return *m_pNet->GetConfig()->GetIPAddress(); + else + return m_pConfig->GetNetworkIPAddress(); +} + +CStatus *CStatus::s_pThis = 0; diff --git a/src/minidexed.h b/src/minidexed.h index 225f1620c..c9df5be78 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -30,7 +30,8 @@ #include "serialmididevice.h" #include "perftimer.h" #include -#include +#include +#include #include #include #include @@ -46,11 +47,12 @@ #include "net/mdnspublisher.h" #include #include "common.h" +#include "status.h" #include "effect_mixer.hpp" -#include "effect_platervbstereo.h" #include "udpmididevice.h" #include "net/ftpdaemon.h" - +#include "effect_chain.h" + class CMiniDexed #ifdef ARM_ALLOW_MULTI_CORE : public CMultiCoreSupport @@ -104,14 +106,35 @@ class CMiniDexed void setBreathController (uint8_t value, unsigned nTG); void setAftertouch (uint8_t value, unsigned nTG); - void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127 - + void SetFX1Send (unsigned nFXSend, unsigned nTG); // 0 .. 99 + void SetFX2Send (unsigned nFXSend, unsigned nTG); // 0 .. 99 + + void SetCompressorEnable (bool compressor, unsigned nTG); // 0 .. 1 (default 1) + void SetCompressorPreGain (int preGain, unsigned nTG); // -20 .. 20 dB (default 0) + void SetCompressorThresh (int thresh, unsigned nTG); // -60 .. 0 dBFS (default -20) + void SetCompressorRatio (unsigned ratio, unsigned nTG); // 1 .. 20 (default 5) + void SetCompressorAttack (unsigned attack, unsigned nTG); // 0 .. 1000 ms (default 5) + void SetCompressorRelease (unsigned release, unsigned nTG); // 0 .. 1000 ms (default 200) + void SetCompressorMakeupGain (int makeupGain, unsigned nTG); // -20 .. 20 dB (default 0) + + void SetEQLow (int nValue, unsigned nTG); + void SetEQMid (int nValue, unsigned nTG); + void SetEQHigh (int nValue, unsigned nTG); + void SetEQGain (int nValue, unsigned nTG); + void SetEQLowMidFreq (unsigned nValue, unsigned nTG); + void SetEQMidHighFreq (unsigned nValue, unsigned nTG); void setMonoMode(uint8_t mono, uint8_t nTG); + void setTGLink(uint8_t nTGLink, uint8_t nTG); + void setEnabled(uint8_t enabled, uint8_t nTG); + void setPitchbendRange(uint8_t range, uint8_t nTG); void setPitchbendStep(uint8_t step, uint8_t nTG); void setPortamentoMode(uint8_t mode, uint8_t nTG); void setPortamentoGlissando(uint8_t glissando, uint8_t nTG); void setPortamentoTime(uint8_t time, uint8_t nTG); + void setNoteLimitLow(unsigned limit, uint8_t nTG); + void setNoteLimitHigh(unsigned limit, uint8_t nTG); + void setNoteShift(int shift, uint8_t nTG); void setModWheelRange(uint8_t range, uint8_t nTG); void setModWheelTarget(uint8_t target, uint8_t nTG); void setFootControllerRange(uint8_t range, uint8_t nTG); @@ -155,22 +178,21 @@ class CMiniDexed bool IsValidPerformance(unsigned nID); bool IsValidPerformanceBank(unsigned nBankID); + int GetLastKeyDown(); + // Must match the order in CUIMenu::TParameter enum TParameter { - ParameterCompressorEnable, - ParameterReverbEnable, - ParameterReverbSize, - ParameterReverbHighDamp, - ParameterReverbLowDamp, - ParameterReverbLowPass, - ParameterReverbDiffusion, - ParameterReverbLevel, ParameterPerformanceSelectChannel, ParameterPerformanceBank, + ParameterMasterVolume, + ParameterMixerDryLevel, + ParameterFXBypass, ParameterUnknown }; + static const unsigned CompressorRatioInf = 31; + void SetParameter (TParameter Parameter, int nValue); int GetParameter (TParameter Parameter); @@ -180,6 +202,9 @@ class CMiniDexed bool DeletePerformance(unsigned nID); bool DoDeletePerformance(void); + void SetFXParameter (FX::TFXParameter Parameter, int nValue, unsigned nFX, bool bSaveOnly = false); + int GetFXParameter (FX::TFXParameter Parameter, unsigned nFX); + // Must match the order in CUIMenu::TGParameter enum TTGParameter { @@ -193,14 +218,20 @@ class CMiniDexed TGParameterCutoff, TGParameterResonance, TGParameterMIDIChannel, - TGParameterReverbSend, + TGParameterFX1Send, + TGParameterFX2Send, TGParameterPitchBendRange, TGParameterPitchBendStep, TGParameterPortamentoMode, TGParameterPortamentoGlissando, TGParameterPortamentoTime, + TGParameterNoteLimitLow, + TGParameterNoteLimitHigh, + TGParameterNoteShift, TGParameterMonoMode, - + TGParameterTGLink, + TGParameterEnabled, + TGParameterMWRange, TGParameterMWPitch, TGParameterMWAmplitude, @@ -220,7 +251,22 @@ class CMiniDexed TGParameterATPitch, TGParameterATAmplitude, TGParameterATEGBias, + + TGParameterCompressorEnable, + TGParameterCompressorPreGain, + TGParameterCompressorThresh, + TGParameterCompressorRatio, + TGParameterCompressorAttack, + TGParameterCompressorRelease, + TGParameterCompressorMakeupGain, + TGParameterEQLow, + TGParameterEQMid, + TGParameterEQHigh, + TGParameterEQGain, + TGParameterEQLowMidFreq, + TGParameterEQMidHighFreq, + TGParameterUnknown }; @@ -238,10 +284,16 @@ class CMiniDexed bool DoSavePerformance (void); void setMasterVolume (float32_t vol); - int GetMasterVolume127() const { return (int)(nMasterVolume >= 1.0f ? 127 : (nMasterVolume <= 0.0f ? 0 : sqrtf(nMasterVolume) * 127.0f)); } bool InitNetwork(); void UpdateNetwork(); + const CIPAddress& GetNetworkIPAddress(); + + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + + void UpdateDAWState (); + void UpdateDAWMenu (CUIMenu::TCPageType Type, s8 ucPage, u8 ucOP, u8 ucTG); private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note @@ -265,7 +317,8 @@ class CMiniDexed CConfig *m_pConfig; int m_nParameter[ParameterUnknown]; // global (non-TG) parameters - + int m_nFXParameter[CConfig::FXChains][FX::FXParameterUnknown]; // FX parameters + unsigned m_nToneGenerators; unsigned m_nPolyphony; @@ -289,7 +342,9 @@ class CMiniDexed unsigned m_nPortamentoGlissando[CConfig::AllToneGenerators]; unsigned m_nPortamentoTime[CConfig::AllToneGenerators]; bool m_bMonoMode[CConfig::AllToneGenerators]; - + unsigned m_nTGLink[CConfig::AllToneGenerators]; + bool m_bEnabled[CConfig::AllToneGenerators]; + unsigned m_nModulationWheelRange[CConfig::AllToneGenerators]; unsigned m_nModulationWheelTarget[CConfig::AllToneGenerators]; unsigned m_nFootControlRange[CConfig::AllToneGenerators]; @@ -303,12 +358,26 @@ class CMiniDexed unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; int m_nNoteShift[CConfig::AllToneGenerators]; - unsigned m_nReverbSend[CConfig::AllToneGenerators]; + unsigned m_nFX1Send[CConfig::AllToneGenerators]; + unsigned m_nFX2Send[CConfig::AllToneGenerators]; + + bool m_bCompressorEnable[CConfig::AllToneGenerators]; + int m_nCompressorPreGain[CConfig::AllToneGenerators]; + int m_nCompressorThresh[CConfig::AllToneGenerators]; + unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; + unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; + unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; + int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; + int m_nEQLow[CConfig::AllToneGenerators]; + int m_nEQMid[CConfig::AllToneGenerators]; + int m_nEQHigh[CConfig::AllToneGenerators]; + int m_nEQGain[CConfig::AllToneGenerators]; + unsigned m_nEQLowMidFreq[CConfig::AllToneGenerators]; + unsigned m_nEQMidHighFreq[CConfig::AllToneGenerators]; + uint8_t m_nRawVoiceData[156]; - - float32_t nMasterVolume; CUserInterface m_UI; CSysExFileLoader m_SysExFileLoader; @@ -317,6 +386,8 @@ class CMiniDexed CMIDIKeyboard *m_pMIDIKeyboard[CConfig::MaxUSBMIDIDevices]; CPCKeyboard m_PCKeyboard; CSerialMIDIDevice m_SerialMIDI; + float32_t m_fMasterVolume[8]; + float32_t m_fMasterVolumeW; bool m_bUseSerial; bool m_bQuadDAC8Chan; @@ -326,19 +397,23 @@ class CMiniDexed #ifdef ARM_ALLOW_MULTI_CORE // unsigned m_nActiveTGsLog2; - volatile TCoreStatus m_CoreStatus[CORES]; - volatile unsigned m_nFramesToProcess; + std::atomic m_CoreStatus[CORES]; + std::atomic m_nFramesToProcess; float32_t m_OutputLevel[CConfig::AllToneGenerators][CConfig::MaxChunkSize]; #endif + int m_nLastKeyDown; + CPerformanceTimer m_GetChunkTimer; bool m_bProfileEnabled; - AudioEffectPlateReverb* reverb; + AudioFXChain* fx_chain[CConfig::FXChains]; AudioStereoMixer* tg_mixer; - AudioStereoMixer* reverb_send_mixer; + AudioStereoMixer* sendfx_mixer[CConfig::FXMixers]; + + CSpinLock m_FXSpinLock; - CSpinLock m_ReverbSpinLock; + CStatus m_Status; // Network CNetSubSystem* m_pNet; @@ -363,6 +438,11 @@ class CMiniDexed bool m_bLoadPerformanceBusy; bool m_bLoadPerformanceBankBusy; bool m_bSaveAsDeault; + + std::atomic m_bVolRampDownWait; + std::atomic m_bVolRampedDown; + + const float32_t m_fRamp; }; #endif diff --git a/src/minidexed.ini b/src/minidexed.ini index 4d0f3895c..ed268452e 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -16,6 +16,9 @@ QuadDAC8Chan=0 # Master Volume (0-127) MasterVolume=64 +# Default "Boot" Screen ( 0=TG1 (default); 1=Performance Load ) +DefaultScreen=0 + # MIDI MIDIBaudRate=31250 #MIDIThru=umidi1,ttyS1 @@ -119,7 +122,8 @@ LongPressTimeout=400 # MIDI Button Navigation # Specify MIDI CC to act as a button (0 = ununsed, so don't use CC 0) -# NB: Off < 64 < ON +# NB: Off < 64 < ON for click / doubleclick / longpress actions +# DEC < 64 < INC for dec / inc actions # CC channel: 0=OFF; 1-16 MIDI Ch; >16 Omni # If MIDIButtonNotes>0 then treat MIDIButton numbers as MIDI # Note numbers, triggered with NoteOn/NoteOff, not CC numbers. @@ -127,20 +131,38 @@ MIDIButtonCh=17 MIDIButtonNotes=0 # Arrow left MIDIButtonPrev=46 +MIDIButtonActionPrev=click # Arrow right MIDIButtonNext=47 +MIDIButtonActionNext=click # Arrow up MIDIButtonBack=48 +MIDIButtonActionBack=click # Arrow down MIDIButtonSelect=49 +MIDIButtonActionSelect=click # Home button MIDIButtonHome=50 +MIDIButtonActionHome=click MIDIButtonPgmUp=51 +MIDIButtonActionPgmUp=click MIDIButtonPgmDown=52 +MIDIButtonActionPgmDown=click MIDIButtonBankUp=53 +MIDIButtonActionBankUp=click MIDIButtonBankDown=54 +MIDIButtonActionBankDown=click MIDIButtonTGUp=55 +MIDIButtonActionTGUp=click MIDIButtonTGDown=56 +MIDIButtonActionTGDown=click + +# Debounce time for dec / inc MIDI messages +# Can be adjusted if the controller sends dec / inc messages too quickly. +MIDIRelativeDebounceTime=0 + +# DAW Controller (Arturia MiniLab 3, KeyLab Essential, KeyLab Essential 3, Keylab mkII) +DAWControllerEnabled=0 # KY-040 Rotary Encoder EncoderEnabled=1 @@ -150,6 +172,7 @@ EncoderPinData=9 # Debug MIDIDumpEnabled=0 ProfileEnabled=0 +LogThrottling=0 # Network NetworkEnabled=0 diff --git a/src/pckeyboard.cpp b/src/pckeyboard.cpp index 79fe92c76..2c7cd3e36 100644 --- a/src/pckeyboard.cpp +++ b/src/pckeyboard.cpp @@ -20,7 +20,7 @@ #include "pckeyboard.h" #include #include -#include +#include struct TKeyInfo { diff --git a/src/performanceconfig.cpp b/src/performanceconfig.cpp index dfff8a9cc..9d5ddeac6 100644 --- a/src/performanceconfig.cpp +++ b/src/performanceconfig.cpp @@ -21,8 +21,10 @@ // along with this program. If not, see . // #include +#include #include "performanceconfig.h" #include "mididevice.h" +#include "common.h" #include #include @@ -161,9 +163,22 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("NoteShift%u", nTG+1); m_nNoteShift[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + PropertyName.Format ("FX1Send%u", nTG+1); + m_nFX1Send[nTG] = m_Properties.GetNumber (PropertyName, 25); + + PropertyName.Format ("FX2Send%u", nTG+1); + m_nFX2Send[nTG] = m_Properties.GetNumber (PropertyName, 0); + + // compatibility ReverbSend[n] => FX1Send[n] PropertyName.Format ("ReverbSend%u", nTG+1); - m_nReverbSend[nTG] = m_Properties.GetNumber (PropertyName, 50); - + if (m_Properties.IsSet (PropertyName)) + { + // the volume calculated by x^4, but FX1Send uses x^2 + float32_t reverbSend = m_Properties.GetNumber (PropertyName, 50); + reverbSend = pow(mapfloat(reverbSend, 0.0f, 99.0f, 0.0f, 1.0f), 2); + m_nFX1Send[nTG] = mapfloat(reverbSend, 0.0f, 1.0f, 0, 99); + } + PropertyName.Format ("PitchBendRange%u", nTG+1); m_nPitchBendRange[nTG] = m_Properties.GetNumber (PropertyName, 2); @@ -184,7 +199,10 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("MonoMode%u", nTG+1); m_bMonoMode[nTG] = m_Properties.GetNumber (PropertyName, 0) != 0; - + + PropertyName.Format ("TGLink%u", nTG+1); + m_nTGLink[nTG] = m_Properties.GetNumber (PropertyName, 0); + PropertyName.Format ("ModulationWheelRange%u", nTG+1); m_nModulationWheelRange[nTG] = m_Properties.GetNumber (PropertyName, 99); @@ -208,18 +226,102 @@ bool CPerformanceConfig::Load (void) PropertyName.Format ("AftertouchTarget%u", nTG+1); m_nAftertouchTarget[nTG] = m_Properties.GetNumber (PropertyName, 0); + + PropertyName.Format ("CompressorEnable%u", nTG+1); + m_bCompressorEnable[nTG] = m_Properties.GetNumber (PropertyName, 0); + PropertyName.Format ("CompressorPreGain%u", nTG+1); + m_nCompressorPreGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("CompressorThresh%u", nTG+1); + m_nCompressorThresh[nTG] = m_Properties.GetSignedNumber (PropertyName, -20); + + PropertyName.Format ("CompressorRatio%u", nTG+1); + m_nCompressorRatio[nTG] = m_Properties.GetNumber (PropertyName, 5); + + PropertyName.Format ("CompressorAttack%u", nTG+1); + m_nCompressorAttack[nTG] = m_Properties.GetNumber (PropertyName, 5); + + PropertyName.Format ("CompressorRelease%u", nTG+1); + m_nCompressorRelease[nTG] = m_Properties.GetNumber (PropertyName, 200); + + PropertyName.Format ("CompressorMakeupGain%u", nTG+1); + m_nCompressorMakeupGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQLow%u", nTG+1); + m_nEQLow[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQMid%u", nTG+1); + m_nEQMid[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQHigh%u", nTG+1); + m_nEQHigh[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQGain%u", nTG+1); + m_nEQGain[nTG] = m_Properties.GetSignedNumber (PropertyName, 0); + + PropertyName.Format ("EQLowMidFreq%u", nTG+1); + m_nEQLowMidFreq[nTG] = m_Properties.GetNumber (PropertyName, 24); + + PropertyName.Format ("EQMidHighFreq%u", nTG+1); + m_nEQMidHighFreq[nTG] = m_Properties.GetNumber (PropertyName, 44); + } + + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + CString PropertyName; + + for (unsigned nParam = 0; nParam < FX::FXParameterUnknown; ++nParam) + { + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + + if (nFX == CConfig::MasterFX) + PropertyName.Format ("MasterFX%s", p.Name); + else + PropertyName.Format ("SendFX%u%s", nFX+1, p.Name); + + if (p.Flags & FX::FXSaveAsString) + m_nFXParameter[nFX][nParam] = FX::getIDFromName(FX::TFXParameter(nParam), m_Properties.GetString (PropertyName, "")); + else + m_nFXParameter[nFX][nParam] = m_Properties.GetSignedNumber (PropertyName, p.Default); } + } - m_bCompressorEnable = m_Properties.GetNumber ("CompressorEnable", 1) != 0; + if (CConfig::FXChains) + { + m_nFXParameter[CConfig::MasterFX][FX::FXParameterReturnLevel] = FX::s_FXParameter[FX::FXParameterReturnLevel].Maximum; + } - m_bReverbEnable = m_Properties.GetNumber ("ReverbEnable", 1) != 0; - m_nReverbSize = m_Properties.GetNumber ("ReverbSize", 70); - m_nReverbHighDamp = m_Properties.GetNumber ("ReverbHighDamp", 50); - m_nReverbLowDamp = m_Properties.GetNumber ("ReverbLowDamp", 50); - m_nReverbLowPass = m_Properties.GetNumber ("ReverbLowPass", 30); - m_nReverbDiffusion = m_Properties.GetNumber ("ReverbDiffusion", 65); - m_nReverbLevel = m_Properties.GetNumber ("ReverbLevel", 99); + m_nMixerDryLevel = m_Properties.GetNumber ("MixerDryLevel", 99); + m_nFXBypass = m_Properties.GetNumber ("FXBypass", 0); + + // Compatibility + if (m_Properties.IsSet ("CompressorEnable") && CConfig::FXChains) + { + bool bHasCompressor = m_Properties.GetNumber ("CompressorEnable", 0); + + m_nFXParameter[CConfig::MasterFX][FX::FXParameterSlot0] = bHasCompressor ? FX::getIDFromName(FX::FXParameterSlot0, "Compressor") : 0; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorPreGain] = 0; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorThresh] = -7; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorRatio] = 5; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorAttack] = 0; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorRelease] = 200; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorHPFilterEnable] = 1; + m_nFXParameter[CConfig::MasterFX][FX::FXParameterCompressorBypass] = 0; + } + + if (m_Properties.IsSet ("ReverbEnable") && CConfig::FXChains) + { + // setup Reverb to FX1 + m_nFXParameter[0][FX::FXParameterSlot0] = FX::getIDFromName(FX::FXParameterSlot0, "PlateReverb"); + m_nFXParameter[0][FX::FXParameterPlateReverbMix] = m_Properties.GetNumber ("ReverbEnable", 1) ? 100 : 0; + m_nFXParameter[0][FX::FXParameterPlateReverbSize] = m_Properties.GetNumber ("ReverbSize", 70); + m_nFXParameter[0][FX::FXParameterPlateReverbHighDamp] = m_Properties.GetNumber ("ReverbHighDamp", 50); + m_nFXParameter[0][FX::FXParameterPlateReverbLowDamp] = m_Properties.GetNumber ("ReverbLowDamp", 50); + m_nFXParameter[0][FX::FXParameterPlateReverbLowPass] = m_Properties.GetNumber ("ReverbLowPass", 30); + m_nFXParameter[0][FX::FXParameterPlateReverbDiffusion] = m_Properties.GetNumber ("ReverbDiffusion", 65); + m_nFXParameter[0][FX::FXParameterReturnLevel] = m_Properties.GetNumber ("ReverbEnable", 1) ? m_Properties.GetNumber ("ReverbLevel", 99) : 0; + } return bResult; } @@ -278,9 +380,12 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("NoteShift%u", nTG+1); m_Properties.SetSignedNumber (PropertyName, m_nNoteShift[nTG]); - PropertyName.Format ("ReverbSend%u", nTG+1); - m_Properties.SetNumber (PropertyName, m_nReverbSend[nTG]); - + PropertyName.Format ("FX1Send%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nFX1Send[nTG]); + + PropertyName.Format ("FX2Send%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nFX2Send[nTG]); + PropertyName.Format ("PitchBendRange%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nPitchBendRange[nTG]); @@ -302,7 +407,10 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("MonoMode%u", nTG+1); m_Properties.SetNumber (PropertyName, m_bMonoMode[nTG] ? 1 : 0); - + + PropertyName.Format ("TGLink%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nTGLink[nTG]); + PropertyName.Format ("ModulationWheelRange%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nModulationWheelRange[nTG]); @@ -327,17 +435,99 @@ bool CPerformanceConfig::Save (void) PropertyName.Format ("AftertouchTarget%u", nTG+1); m_Properties.SetNumber (PropertyName, m_nAftertouchTarget[nTG]); + PropertyName.Format ("CompressorEnable%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_bCompressorEnable[nTG]); + + PropertyName.Format ("CompressorPreGain%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorPreGain[nTG]); + + PropertyName.Format ("CompressorThresh%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorThresh[nTG]); + + PropertyName.Format ("CompressorRatio%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nCompressorRatio[nTG]); + + PropertyName.Format ("CompressorAttack%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nCompressorAttack[nTG]); + + PropertyName.Format ("CompressorRelease%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nCompressorRelease[nTG]); + + PropertyName.Format ("CompressorMakeupGain%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nCompressorMakeupGain[nTG]); + + PropertyName.Format ("EQLow%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQLow[nTG]); + + PropertyName.Format ("EQMid%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQMid[nTG]); + + PropertyName.Format ("EQHigh%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQHigh[nTG]); + + PropertyName.Format ("EQGain%u", nTG+1); + m_Properties.SetSignedNumber (PropertyName, m_nEQGain[nTG]); + + PropertyName.Format ("EQLowMidFreq%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nEQLowMidFreq[nTG]); + + PropertyName.Format ("EQMidHighFreq%u", nTG+1); + m_Properties.SetNumber (PropertyName, m_nEQMidHighFreq[nTG]); + + } + + for (unsigned nFX = 0; nFX < CConfig::FXChains; ++nFX) + { + CString PropertyName; + + CString FXName; + if (nFX == CConfig::MasterFX) + FXName = "MasterFX"; + else + FXName.Format ("SendFX%u", nFX+1); + + for (unsigned nSlot = 0; nSlot < 3; ++nSlot) + { + unsigned nSlotParam = FX::FXParameterSlot0 + nSlot; + unsigned nEffectID = m_nFXParameter[nFX][nSlotParam]; + const FX::EffectType &effect = FX::s_effects[nEffectID]; + + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[nSlotParam].Name); + m_Properties.SetString (PropertyName, effect.Name); } - m_Properties.SetNumber ("CompressorEnable", m_bCompressorEnable ? 1 : 0); + for (unsigned nSlot = 0; nSlot < 3; ++nSlot) + { + unsigned nSlotParam = FX::FXParameterSlot0 + nSlot; + unsigned nEffectID = m_nFXParameter[nFX][nSlotParam]; + const FX::EffectType &effect = FX::s_effects[nEffectID]; - m_Properties.SetNumber ("ReverbEnable", m_bReverbEnable ? 1 : 0); - m_Properties.SetNumber ("ReverbSize", m_nReverbSize); - m_Properties.SetNumber ("ReverbHighDamp", m_nReverbHighDamp); - m_Properties.SetNumber ("ReverbLowDamp", m_nReverbLowDamp); - m_Properties.SetNumber ("ReverbLowPass", m_nReverbLowPass); - m_Properties.SetNumber ("ReverbDiffusion", m_nReverbDiffusion); - m_Properties.SetNumber ("ReverbLevel", m_nReverbLevel); + if (nEffectID == 0) continue; + + for (unsigned nParam = effect.MinID; nParam <= effect.MaxID; ++nParam) + { + const FX::FXParameterType &p = FX::s_FXParameter[nParam]; + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[nParam].Name); + + if (p.Flags & FX::FXSaveAsString) + m_Properties.SetString (PropertyName, FX::getNameFromID(FX::TFXParameter(nParam), m_nFXParameter[nFX][nParam])); + else + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][nParam]); + } + } + + if (nFX != CConfig::MasterFX) + { + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[FX::FXParameterReturnLevel].Name); + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][FX::FXParameterReturnLevel]); + } + + PropertyName.Format ("%s%s", (const char*)FXName, FX::s_FXParameter[FX::FXParameterBypass].Name); + m_Properties.SetSignedNumber (PropertyName, m_nFXParameter[nFX][FX::FXParameterBypass]); + } + + m_Properties.SetNumber ("MixerDryLevel", m_nMixerDryLevel); + m_Properties.SetNumber ("FXBypass", m_nFXBypass); return m_Properties.Save (); } @@ -408,10 +598,16 @@ int CPerformanceConfig::GetNoteShift (unsigned nTG) const return m_nNoteShift[nTG]; } -unsigned CPerformanceConfig::GetReverbSend (unsigned nTG) const +unsigned CPerformanceConfig::GetFX1Send (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nFX1Send[nTG]; +} + +unsigned CPerformanceConfig::GetFX2Send (unsigned nTG) const { assert (nTG < CConfig::AllToneGenerators); - return m_nReverbSend[nTG]; + return m_nFX2Send[nTG]; } void CPerformanceConfig::SetBankNumber (unsigned nValue, unsigned nTG) @@ -480,91 +676,124 @@ void CPerformanceConfig::SetNoteShift (int nValue, unsigned nTG) m_nNoteShift[nTG] = nValue; } -void CPerformanceConfig::SetReverbSend (unsigned nValue, unsigned nTG) +void CPerformanceConfig::SetFX1Send (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); - m_nReverbSend[nTG] = nValue; + m_nFX1Send[nTG] = nValue; } -bool CPerformanceConfig::GetCompressorEnable (void) const +void CPerformanceConfig::SetFX2Send (unsigned nValue, unsigned nTG) { - return m_bCompressorEnable; + assert (nTG < CConfig::AllToneGenerators); + m_nFX2Send[nTG] = nValue; } -bool CPerformanceConfig::GetReverbEnable (void) const +int CPerformanceConfig::GetEQLow (unsigned nTG) const { - return m_bReverbEnable; + assert (nTG < CConfig::AllToneGenerators); + return m_nEQLow[nTG]; } -unsigned CPerformanceConfig::GetReverbSize (void) const +int CPerformanceConfig::GetEQMid (unsigned nTG) const { - return m_nReverbSize; + assert (nTG < CConfig::AllToneGenerators); + return m_nEQMid[nTG]; +} + +int CPerformanceConfig::GetEQHigh (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQHigh[nTG]; +} + +int CPerformanceConfig::GetEQGain (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQGain[nTG]; +} + +unsigned CPerformanceConfig::GetEQLowMidFreq (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nEQLowMidFreq[nTG]; } -unsigned CPerformanceConfig::GetReverbHighDamp (void) const +unsigned CPerformanceConfig::GetEQMidHighFreq (unsigned nTG) const { - return m_nReverbHighDamp; + assert (nTG < CConfig::AllToneGenerators); + return m_nEQMidHighFreq[nTG]; } -unsigned CPerformanceConfig::GetReverbLowDamp (void) const +void CPerformanceConfig::SetEQLow (int nValue, unsigned nTG) { - return m_nReverbLowDamp; + assert (nTG < CConfig::AllToneGenerators); + m_nEQLow[nTG] = nValue; } -unsigned CPerformanceConfig::GetReverbLowPass (void) const +void CPerformanceConfig::SetEQMid (int nValue, unsigned nTG) { - return m_nReverbLowPass; + assert (nTG < CConfig::AllToneGenerators); + m_nEQMid[nTG] = nValue; } -unsigned CPerformanceConfig::GetReverbDiffusion (void) const +void CPerformanceConfig::SetEQHigh (int nValue, unsigned nTG) { - return m_nReverbDiffusion; + assert (nTG < CConfig::AllToneGenerators); + m_nEQHigh[nTG] = nValue; } -unsigned CPerformanceConfig::GetReverbLevel (void) const +void CPerformanceConfig::SetEQGain (int nValue, unsigned nTG) { - return m_nReverbLevel; + assert (nTG < CConfig::AllToneGenerators); + m_nEQGain[nTG] = nValue; } -void CPerformanceConfig::SetCompressorEnable (bool bValue) +void CPerformanceConfig::SetEQLowMidFreq (unsigned nValue, unsigned nTG) { - m_bCompressorEnable = bValue; + assert (nTG < CConfig::AllToneGenerators); + m_nEQLowMidFreq[nTG] = nValue; } -void CPerformanceConfig::SetReverbEnable (bool bValue) +void CPerformanceConfig::SetEQMidHighFreq (unsigned nValue, unsigned nTG) { - m_bReverbEnable = bValue; + assert (nTG < CConfig::AllToneGenerators); + m_nEQMidHighFreq[nTG] = nValue; } -void CPerformanceConfig::SetReverbSize (unsigned nValue) +int CPerformanceConfig::GetFXParameter (FX::TFXParameter nParameter, unsigned nFX) const { - m_nReverbSize = nValue; + assert (nFX < CConfig::FXChains); + assert (nParameter < FX::FXParameterUnknown); + return m_nFXParameter[nFX][nParameter]; } -void CPerformanceConfig::SetReverbHighDamp (unsigned nValue) +void CPerformanceConfig::SetFXParameter (FX::TFXParameter nParameter, int nValue, unsigned nFX) { - m_nReverbHighDamp = nValue; + assert (nFX < CConfig::FXChains); + assert (nParameter < FX::FXParameterUnknown); + m_nFXParameter[nFX][nParameter] = nValue; } -void CPerformanceConfig::SetReverbLowDamp (unsigned nValue) +unsigned CPerformanceConfig::GetMixerDryLevel () const { - m_nReverbLowDamp = nValue; + return m_nMixerDryLevel; } -void CPerformanceConfig::SetReverbLowPass (unsigned nValue) +void CPerformanceConfig::SetMixerDryLevel (unsigned nValue) { - m_nReverbLowPass = nValue; + m_nMixerDryLevel = nValue; } -void CPerformanceConfig::SetReverbDiffusion (unsigned nValue) +unsigned CPerformanceConfig::GetFXBypass () const { - m_nReverbDiffusion = nValue; + return m_nFXBypass; } -void CPerformanceConfig::SetReverbLevel (unsigned nValue) +void CPerformanceConfig::SetFXBypass (unsigned nValue) { - m_nReverbLevel = nValue; + m_nFXBypass = nValue; } + // Pitch bender and portamento: void CPerformanceConfig::SetPitchBendRange (unsigned nValue, unsigned nTG) { @@ -641,6 +870,17 @@ bool CPerformanceConfig::GetMonoMode (unsigned nTG) const return m_bMonoMode[nTG]; } +void CPerformanceConfig::SetTGLink (unsigned nTGLink, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nTGLink[nTG] = nTGLink; +} + +unsigned CPerformanceConfig::GetTGLink (unsigned nTG) const +{ + return m_nTGLink[nTG]; +} + void CPerformanceConfig::SetModulationWheelRange (unsigned nValue, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -737,6 +977,91 @@ unsigned CPerformanceConfig::GetAftertouchTarget (unsigned nTG) const return m_nAftertouchTarget[nTG]; } +void CPerformanceConfig::SetCompressorEnable (bool bValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_bCompressorEnable[nTG] = bValue; +} + +bool CPerformanceConfig::GetCompressorEnable (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_bCompressorEnable[nTG]; +} + +void CPerformanceConfig::SetCompressorPreGain (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorPreGain[nTG] = nValue; +} + +int CPerformanceConfig::GetCompressorPreGain (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorPreGain[nTG]; +} + +void CPerformanceConfig::SetCompressorThresh (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorThresh[nTG] = nValue; +} + +int CPerformanceConfig::GetCompressorThresh (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorThresh[nTG]; +} + +void CPerformanceConfig::SetCompressorRatio (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorRatio[nTG] = nValue; +} + +unsigned CPerformanceConfig::GetCompressorRatio (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorRatio[nTG]; +} + +void CPerformanceConfig::SetCompressorAttack (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorAttack[nTG] = nValue; +} + +unsigned CPerformanceConfig::GetCompressorAttack (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorAttack[nTG]; +} + +void CPerformanceConfig::SetCompressorRelease (unsigned nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorRelease[nTG] = nValue; +} + +unsigned CPerformanceConfig::GetCompressorRelease (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorRelease[nTG]; +} + +void CPerformanceConfig::SetCompressorMakeupGain (int nValue, unsigned nTG) +{ + assert (nTG < CConfig::AllToneGenerators); + m_nCompressorMakeupGain[nTG] = nValue; +} + +int CPerformanceConfig::GetCompressorMakeupGain (unsigned nTG) const +{ + assert (nTG < CConfig::AllToneGenerators); + return m_nCompressorMakeupGain[nTG]; +} + + void CPerformanceConfig::SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG) { assert (nTG < CConfig::AllToneGenerators); @@ -953,13 +1278,13 @@ bool CPerformanceConfig::CreateNewPerformanceFile(void) FRESULT Result = f_open (&File, nFileName.c_str(), FA_WRITE | FA_CREATE_ALWAYS); if (Result != FR_OK) { - m_PerformanceFileName[nNewPerformance]=nullptr; + m_PerformanceFileName[nNewPerformance].clear(); return false; } if (f_close (&File) != FR_OK) { - m_PerformanceFileName[nNewPerformance]=nullptr; + m_PerformanceFileName[nNewPerformance].clear(); return false; } diff --git a/src/performanceconfig.h b/src/performanceconfig.h index 916a2eec0..549da1026 100644 --- a/src/performanceconfig.h +++ b/src/performanceconfig.h @@ -26,6 +26,7 @@ #include "config.h" #include #include +#include "effect.h" #define NUM_VOICE_PARAM 156 #define NUM_PERFORMANCES 128 #define NUM_PERFORMANCE_BANKS 128 @@ -54,13 +55,15 @@ class CPerformanceConfig // Performance configuration unsigned GetNoteLimitLow (unsigned nTG) const; // 0 .. 127 unsigned GetNoteLimitHigh (unsigned nTG) const; // 0 .. 127 int GetNoteShift (unsigned nTG) const; // -24 .. 24 - unsigned GetReverbSend (unsigned nTG) const; // 0 .. 127 + unsigned GetFX1Send (unsigned nTG) const; // 0 .. 99 + unsigned GetFX2Send (unsigned nTG) const; // 0 .. 99 unsigned GetPitchBendRange (unsigned nTG) const; // 0 .. 12 unsigned GetPitchBendStep (unsigned nTG) const; // 0 .. 12 unsigned GetPortamentoMode (unsigned nTG) const; // 0 .. 1 unsigned GetPortamentoGlissando (unsigned nTG) const; // 0 .. 1 unsigned GetPortamentoTime (unsigned nTG) const; // 0 .. 99 bool GetMonoMode (unsigned nTG) const; // 0 .. 1 + unsigned GetTGLink (unsigned nTG) const; // 0 .. 4 unsigned GetModulationWheelRange (unsigned nTG) const; // 0 .. 99 unsigned GetModulationWheelTarget (unsigned nTG) const; // 0 .. 7 @@ -71,6 +74,14 @@ class CPerformanceConfig // Performance configuration unsigned GetAftertouchRange (unsigned nTG) const; // 0 .. 99 unsigned GetAftertouchTarget (unsigned nTG) const; // 0 .. 7 + bool GetCompressorEnable (unsigned nTG) const; // 0 .. 1 + int GetCompressorPreGain (unsigned nTG) const; + int GetCompressorThresh (unsigned nTG) const; + unsigned GetCompressorRatio (unsigned nTG) const; + unsigned GetCompressorAttack (unsigned nTG) const; + unsigned GetCompressorRelease (unsigned nTG) const; + int GetCompressorMakeupGain (unsigned nTG) const; + void SetBankNumber (unsigned nValue, unsigned nTG); void SetVoiceNumber (unsigned nValue, unsigned nTG); void SetMIDIChannel (unsigned nValue, unsigned nTG); @@ -82,7 +93,8 @@ class CPerformanceConfig // Performance configuration void SetNoteLimitLow (unsigned nValue, unsigned nTG); void SetNoteLimitHigh (unsigned nValue, unsigned nTG); void SetNoteShift (int nValue, unsigned nTG); - void SetReverbSend (unsigned nValue, unsigned nTG); + void SetFX1Send (unsigned nValue, unsigned nTG); + void SetFX2Send (unsigned nValue, unsigned nTG); void SetPitchBendRange (unsigned nValue, unsigned nTG); void SetPitchBendStep (unsigned nValue, unsigned nTG); void SetPortamentoMode (unsigned nValue, unsigned nTG); @@ -91,6 +103,7 @@ class CPerformanceConfig // Performance configuration void SetVoiceDataToTxt (const uint8_t *pData, unsigned nTG); uint8_t *GetVoiceDataFromTxt (unsigned nTG); void SetMonoMode (bool bOKValue, unsigned nTG); + void SetTGLink (unsigned nTGLink, unsigned nTG); void SetModulationWheelRange (unsigned nValue, unsigned nTG); void SetModulationWheelTarget (unsigned nValue, unsigned nTG); @@ -101,24 +114,37 @@ class CPerformanceConfig // Performance configuration void SetAftertouchRange (unsigned nValue, unsigned nTG); void SetAftertouchTarget (unsigned nValue, unsigned nTG); + void SetCompressorEnable (bool nValue, unsigned nTG); + void SetCompressorPreGain (int nValue, unsigned nTG); + void SetCompressorThresh (int nValue, unsigned nTG); + void SetCompressorRatio (unsigned nValue, unsigned nTG); + void SetCompressorAttack (unsigned nValue, unsigned nTG); + void SetCompressorRelease (unsigned nValue, unsigned nTG); + void SetCompressorMakeupGain (int nValue, unsigned nTG); + + int GetEQLow (unsigned nTG) const; + int GetEQMid (unsigned nTG) const; + int GetEQHigh (unsigned nTG) const; + int GetEQGain (unsigned nTG) const; + unsigned GetEQLowMidFreq (unsigned nTG) const; + unsigned GetEQMidHighFreq (unsigned nTG) const; + + void SetEQLow (int nValue, unsigned nTG); + void SetEQMid (int nValue, unsigned nTG); + void SetEQHigh (int nValue, unsigned nTG); + void SetEQGain (int nValue, unsigned nTG); + void SetEQLowMidFreq (unsigned nValue, unsigned nTG); + void SetEQMidHighFreq (unsigned nValue, unsigned nTG); + // Effects - bool GetCompressorEnable (void) const; - bool GetReverbEnable (void) const; - unsigned GetReverbSize (void) const; // 0 .. 99 - unsigned GetReverbHighDamp (void) const; // 0 .. 99 - unsigned GetReverbLowDamp (void) const; // 0 .. 99 - unsigned GetReverbLowPass (void) const; // 0 .. 99 - unsigned GetReverbDiffusion (void) const; // 0 .. 99 - unsigned GetReverbLevel (void) const; // 0 .. 99 - - void SetCompressorEnable (bool bValue); - void SetReverbEnable (bool bValue); - void SetReverbSize (unsigned nValue); - void SetReverbHighDamp (unsigned nValue); - void SetReverbLowDamp (unsigned nValue); - void SetReverbLowPass (unsigned nValue); - void SetReverbDiffusion (unsigned nValue); - void SetReverbLevel (unsigned nValue); + int GetFXParameter (FX::TFXParameter nParameter, unsigned nFX) const; + void SetFXParameter (FX::TFXParameter nParameter, int nValue, unsigned nFX); + + unsigned GetMixerDryLevel () const; + void SetMixerDryLevel (unsigned nValue); + + unsigned GetFXBypass () const; + void SetFXBypass (unsigned nValue); bool VoiceDataFilled(unsigned nTG); bool ListPerformances(); @@ -165,7 +191,8 @@ class CPerformanceConfig // Performance configuration unsigned m_nNoteLimitLow[CConfig::AllToneGenerators]; unsigned m_nNoteLimitHigh[CConfig::AllToneGenerators]; int m_nNoteShift[CConfig::AllToneGenerators]; - int m_nReverbSend[CConfig::AllToneGenerators]; + int m_nFX1Send[CConfig::AllToneGenerators]; + int m_nFX2Send[CConfig::AllToneGenerators]; unsigned m_nPitchBendRange[CConfig::AllToneGenerators]; unsigned m_nPitchBendStep[CConfig::AllToneGenerators]; unsigned m_nPortamentoMode[CConfig::AllToneGenerators]; @@ -173,6 +200,7 @@ class CPerformanceConfig // Performance configuration unsigned m_nPortamentoTime[CConfig::AllToneGenerators]; std::string m_nVoiceDataTxt[CConfig::AllToneGenerators]; bool m_bMonoMode[CConfig::AllToneGenerators]; + unsigned m_nTGLink[CConfig::AllToneGenerators]; unsigned m_nModulationWheelRange[CConfig::AllToneGenerators]; unsigned m_nModulationWheelTarget[CConfig::AllToneGenerators]; @@ -181,7 +209,22 @@ class CPerformanceConfig // Performance configuration unsigned m_nBreathControlRange[CConfig::AllToneGenerators]; unsigned m_nBreathControlTarget[CConfig::AllToneGenerators]; unsigned m_nAftertouchRange[CConfig::AllToneGenerators]; - unsigned m_nAftertouchTarget[CConfig::AllToneGenerators]; + unsigned m_nAftertouchTarget[CConfig::AllToneGenerators]; + + bool m_bCompressorEnable[CConfig::AllToneGenerators]; + int m_nCompressorPreGain[CConfig::AllToneGenerators]; + int m_nCompressorThresh[CConfig::AllToneGenerators]; + unsigned m_nCompressorRatio[CConfig::AllToneGenerators]; + unsigned m_nCompressorAttack[CConfig::AllToneGenerators]; + unsigned m_nCompressorRelease[CConfig::AllToneGenerators]; + int m_nCompressorMakeupGain[CConfig::AllToneGenerators]; + + int m_nEQLow[CConfig::AllToneGenerators]; + int m_nEQMid[CConfig::AllToneGenerators]; + int m_nEQHigh[CConfig::AllToneGenerators]; + int m_nEQGain[CConfig::AllToneGenerators]; + unsigned m_nEQLowMidFreq[CConfig::AllToneGenerators]; + unsigned m_nEQMidHighFreq[CConfig::AllToneGenerators]; unsigned m_nLastPerformance; unsigned m_nActualPerformance = 0; @@ -195,15 +238,11 @@ class CPerformanceConfig // Performance configuration FATFS *m_pFileSystem; std::string NewPerformanceName=""; - - bool m_bCompressorEnable; - bool m_bReverbEnable; - unsigned m_nReverbSize; - unsigned m_nReverbHighDamp; - unsigned m_nReverbLowDamp; - unsigned m_nReverbLowPass; - unsigned m_nReverbDiffusion; - unsigned m_nReverbLevel; + + int m_nFXParameter[CConfig::FXChains][FX::FXParameterUnknown]; + + unsigned m_nMixerDryLevel; + unsigned m_nFXBypass; }; #endif diff --git a/src/perftimer.cpp b/src/perftimer.cpp index 5a21471b5..878642703 100644 --- a/src/perftimer.cpp +++ b/src/perftimer.cpp @@ -18,6 +18,7 @@ // along with this program. If not, see . // #include "perftimer.h" +#include #include CPerformanceTimer::CPerformanceTimer (const char *pName, unsigned nDeadlineMicros) @@ -36,11 +37,11 @@ void CPerformanceTimer::Start (void) void CPerformanceTimer::Stop (void) { unsigned nEndTicks = CTimer::GetClockTicks (); - unsigned nMicros = (nEndTicks - m_nStartTicks) / (CLOCKHZ / 1000000); + m_nLastMicros = (nEndTicks - m_nStartTicks) / (CLOCKHZ / 1000000); - if (nMicros > m_nMaximumMicros) + if (m_nLastMicros > m_nMaximumMicros) { - m_nMaximumMicros = nMicros; + m_nMaximumMicros = m_nLastMicros; } } @@ -53,14 +54,27 @@ void CPerformanceTimer::Dump (unsigned nIntervalTicks) m_nLastDumpTicks = nTicks; unsigned nMaximumMicros = m_nMaximumMicros; // may be overwritten from interrupt + unsigned nLastMicros = m_nLastMicros; - std::cout << m_Name << ": Maximum duration was " << nMaximumMicros << "us"; + std::cout << m_Name << ": Last duration was " << nLastMicros << "us"; + + if (m_nDeadlineMicros != 0) + { + std::cout << " (" << nLastMicros*100 / m_nDeadlineMicros << "%)"; + } + + std::cout << " Maximum was " << nMaximumMicros << "us"; if (m_nDeadlineMicros != 0) { std::cout << " (" << nMaximumMicros*100 / m_nDeadlineMicros << "%)"; } + CCPUThrottle *pCPUT = CCPUThrottle::Get (); + + std::cout << " (CPU " << pCPUT->GetClockRate () / 1000000 << "/" << pCPUT->GetMaxClockRate() / 1000000 << " MHz "; + std::cout << pCPUT->GetTemperature () << "/" << pCPUT->GetMaxTemperature () << " C)"; + std::cout << std::endl; } } diff --git a/src/perftimer.h b/src/perftimer.h index 537b6d0da..91c0ae4ab 100644 --- a/src/perftimer.h +++ b/src/perftimer.h @@ -38,6 +38,7 @@ class CPerformanceTimer unsigned m_nDeadlineMicros; unsigned m_nStartTicks; + unsigned m_nLastMicros; unsigned m_nMaximumMicros; unsigned m_nLastDumpTicks; diff --git a/src/serialmididevice.cpp b/src/serialmididevice.cpp index 3fe01e8f9..42ffcd2cf 100644 --- a/src/serialmididevice.cpp +++ b/src/serialmididevice.cpp @@ -24,7 +24,7 @@ #include #include #include "serialmididevice.h" -#include +#include LOGMODULE("serialmididevice"); diff --git a/src/status.h b/src/status.h new file mode 100644 index 000000000..b35800441 --- /dev/null +++ b/src/status.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +class CStatus +{ +public: + CStatus (unsigned nUpdateSecs = 3): + nCPUMaxTemp{CCPUThrottle::Get ()->GetMaxTemperature ()}, + nCPUMaxClockRate{CCPUThrottle::Get ()->GetMaxClockRate ()}, + m_nUpdateTicks{nUpdateSecs*CLOCKHZ}, + m_nLastTicks{} + { + assert (s_pThis == 0); + s_pThis = this; + assert (s_pThis != 0); + } + + ~CStatus () + { + s_pThis = 0; + } + + void Update () + { + unsigned nTicks = CTimer::GetClockTicks (); + + if (nTicks - m_nLastTicks >= m_nUpdateTicks) + { + m_nLastTicks = nTicks; + + CCPUThrottle *pCPUT = CCPUThrottle::Get (); + + nCPUTemp = pCPUT->GetTemperature (); + nCPUClockRate = pCPUT->GetClockRate (); + } + } + + static CStatus *Get () + { + assert (s_pThis != 0); + return s_pThis; + } + + std::atomic nCPUTemp; + const unsigned nCPUMaxTemp; + std::atomic nCPUClockRate; + const unsigned nCPUMaxClockRate; + +private: + unsigned m_nUpdateTicks; + unsigned m_nLastTicks; + + static CStatus *s_pThis; +}; diff --git a/src/sysexfileloader.cpp b/src/sysexfileloader.cpp index 6b83f5b50..5e2634d78 100644 --- a/src/sysexfileloader.cpp +++ b/src/sysexfileloader.cpp @@ -18,12 +18,12 @@ // along with this program. If not, see . // #include "sysexfileloader.h" -#include +#include #include -#include -#include +#include +#include #include -#include +#include #include #include "voices.c" diff --git a/src/udpmididevice.cpp b/src/udpmididevice.cpp index 000bc3d1e..f78d5581e 100644 --- a/src/udpmididevice.cpp +++ b/src/udpmididevice.cpp @@ -24,7 +24,7 @@ #include #include #include "udpmididevice.h" -#include +#include #include #include diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index 06eb85762..95a708f5b 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -19,9 +19,9 @@ // #include "uibuttons.h" #include -#include +#include #include -#include +#include #include "midi.h" LOGMODULE ("uibuttons"); @@ -37,8 +37,11 @@ CUIButton::CUIButton (void) m_clickEvent(BtnEventNone), m_doubleClickEvent(BtnEventNone), m_longPressEvent(BtnEventNone), + m_decEvent(BtnEventNone), + m_incEvent(BtnEventNone), m_doubleClickTimeout(0), - m_longPressTimeout(0) + m_longPressTimeout(0), + m_MIDIRelativeDebounceTime(0) { } @@ -60,7 +63,7 @@ void CUIButton::reset (void) m_numClicks = 0; } -boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout) +boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout, unsigned MIDIRelativeDebounceTime) { assert (!m_pin); assert(longPressTimeout >= doubleClickTimeout); @@ -68,6 +71,7 @@ boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, m_pinNumber = pinNumber; m_doubleClickTimeout = doubleClickTimeout; m_longPressTimeout = longPressTimeout; + m_MIDIRelativeDebounceTime = MIDIRelativeDebounceTime; // Initialise timing values m_timer = m_longPressTimeout; @@ -102,6 +106,16 @@ void CUIButton::setLongPressEvent(BtnEvent longPressEvent) m_longPressEvent = longPressEvent; } +void CUIButton::setDecEvent(BtnEvent decEvent) +{ + m_decEvent = decEvent; +} + +void CUIButton::setIncEvent(BtnEvent incEvent) +{ + m_incEvent = incEvent; +} + unsigned CUIButton::getPinNumber(void) { return m_pinNumber; @@ -110,6 +124,7 @@ unsigned CUIButton::getPinNumber(void) CUIButton::BtnTrigger CUIButton::ReadTrigger (void) { unsigned value; + if (isMidiPin(m_pinNumber)) { if (!m_midipin) @@ -117,7 +132,26 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void) // Always return "not pressed" if not configured return BtnTriggerNone; } - value = m_midipin->Read(); + + if (m_decEvent || m_incEvent) + { + value = m_midipin->Read(); + + // reset value to trigger only once + m_midipin->Write(MIDIPIN_CENTER); + m_debounceTimer++; + + if (value == MIDIPIN_CENTER || m_debounceTimer < m_MIDIRelativeDebounceTime) + return BtnTriggerNone; + + m_debounceTimer = 0; + return value < MIDIPIN_CENTER ? BtnTriggerDec : BtnTriggerInc; + } + else + { + // Simulates a PULLUP IO pin, so "true" is LOW (0) + value = m_midipin->Read() < MIDIPIN_CENTER ? HIGH : LOW; + } } else { @@ -231,6 +265,12 @@ CUIButton::BtnEvent CUIButton::Read (void) { else if (trigger == BtnTriggerLongPress) { return m_longPressEvent; } + else if (trigger == BtnTriggerDec) { + return m_decEvent; + } + else if (trigger == BtnTriggerInc) { + return m_incEvent; + } assert (trigger == BtnTriggerNone); @@ -251,6 +291,12 @@ CUIButton::BtnTrigger CUIButton::triggerTypeFromString(const char* triggerString else if (strcmp(triggerString, "longpress") == 0) { return BtnTriggerLongPress; } + else if (strcmp(triggerString, "dec") == 0) { + return BtnTriggerDec; + } + else if (strcmp(triggerString, "inc") == 0) { + return BtnTriggerInc; + } LOGERR("Invalid action: %s", triggerString); @@ -273,9 +319,6 @@ boolean CUIButtons::Initialize (void) { assert (m_pConfig); - // Read the button configuration - m_doubleClickTimeout = m_pConfig->GetDoubleClickTimeout (); - m_longPressTimeout = m_pConfig->GetLongPressTimeout (); m_prevPin = m_pConfig->GetButtonPinPrev (); m_prevAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionPrev ()); m_nextPin = m_pConfig->GetButtonPinNext (); @@ -300,28 +343,40 @@ boolean CUIButtons::Initialize (void) m_TGDownAction = CUIButton::triggerTypeFromString( m_pConfig->GetButtonActionTGDown ()); m_notesMidi = ccToMidiPin( m_pConfig->GetMIDIButtonNotes ()); m_prevMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPrev ()); + m_prevMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionPrev ()); m_nextMidi = ccToMidiPin( m_pConfig->GetMIDIButtonNext ()); + m_nextMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionNext ()); m_backMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBack ()); + m_backMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionBack ()); m_selectMidi = ccToMidiPin( m_pConfig->GetMIDIButtonSelect ()); + m_selectMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionSelect ()); m_homeMidi = ccToMidiPin( m_pConfig->GetMIDIButtonHome ()); + m_homeMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionHome ()); m_pgmUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPgmUp ()); + m_pgmUpMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionPgmUp ()); m_pgmDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonPgmDown ()); + m_pgmDownMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionPgmDown ()); m_BankUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBankUp ()); + m_BankUpMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionBankUp ()); m_BankDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonBankDown ()); + m_BankDownMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionBankDown ()); m_TGUpMidi = ccToMidiPin( m_pConfig->GetMIDIButtonTGUp ()); + m_TGUpMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionTGUp ()); m_TGDownMidi = ccToMidiPin( m_pConfig->GetMIDIButtonTGDown ()); - + m_TGDownMidiAction = CUIButton::triggerTypeFromString( m_pConfig->GetMIDIButtonActionTGDown ()); + // First sanity check and convert the timeouts: // Internally values are in tenths of a millisecond, but config values // are in milliseconds - unsigned doubleClickTimeout = m_doubleClickTimeout * 10; - unsigned longPressTimeout = m_longPressTimeout * 10; + unsigned doubleClickTimeout = m_pConfig->GetDoubleClickTimeout () * 10; + unsigned longPressTimeout = m_pConfig->GetLongPressTimeout () * 10; + unsigned MIDIRelativeDebounceTime = m_pConfig->GetMIDIRelativeDebounceTime () * 10; if (longPressTimeout < doubleClickTimeout) { // This is invalid - long press must be longest timeout LOGERR("LongPressTimeout (%u) should not be shorter than DoubleClickTimeout (%u)", - m_longPressTimeout, - m_doubleClickTimeout); + longPressTimeout / 10, + doubleClickTimeout / 10); // Just make long press as long as double click longPressTimeout = doubleClickTimeout; @@ -329,7 +384,7 @@ boolean CUIButtons::Initialize (void) // Each normal button can be assigned up to 3 actions: click, doubleclick and // longpress. We may not initialise all of the buttons. - // MIDI buttons only support a single click. + // MIDI buttons can be assigned to click, doubleclick, longpress, dec, inc unsigned pins[MAX_BUTTONS] = { m_prevPin, m_nextPin, m_backPin, m_selectPin, m_homePin, m_pgmUpPin, m_pgmDownPin, m_BankUpPin, m_BankDownPin, m_TGUpPin, m_TGDownPin, m_prevMidi, m_nextMidi, m_backMidi, m_selectMidi, m_homeMidi, m_pgmUpMidi, m_pgmDownMidi, m_BankUpMidi, m_BankDownMidi, m_TGUpMidi, m_TGDownMidi @@ -338,9 +393,9 @@ boolean CUIButtons::Initialize (void) // Normal buttons m_prevAction, m_nextAction, m_backAction, m_selectAction, m_homeAction, m_pgmUpAction, m_pgmDownAction, m_BankUpAction, m_BankDownAction, m_TGUpAction, m_TGDownAction, - // MIDI Buttons only support a single click (at present) - CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, - CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick, CUIButton::BtnTriggerClick + // MIDI buttons + m_prevMidiAction, m_nextMidiAction, m_backMidiAction, m_selectMidiAction, m_homeMidiAction, + m_pgmUpMidiAction, m_pgmDownMidiAction, m_BankUpMidiAction, m_BankDownMidiAction, m_TGUpMidiAction, m_TGDownMidiAction, }; CUIButton::BtnEvent events[MAX_BUTTONS] = { // Normal buttons @@ -387,7 +442,7 @@ boolean CUIButtons::Initialize (void) } else if (m_buttons[j].getPinNumber() == 0) { // This is un-initialised so can be assigned - m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout); + m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout, MIDIRelativeDebounceTime); break; } } @@ -406,7 +461,7 @@ boolean CUIButtons::Initialize (void) if (m_buttons[j].getPinNumber() == 0) { // This is un-initialised so can be assigned // doubleClickTimeout and longPressTimeout are ignored for MIDI buttons at present - m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout); + m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout, MIDIRelativeDebounceTime); break; } } @@ -440,6 +495,12 @@ void CUIButtons::bindButton(unsigned pinNumber, CUIButton::BtnTrigger trigger, C else if (trigger == CUIButton::BtnTriggerLongPress) { m_buttons[i].setLongPressEvent(event); } + else if (trigger == CUIButton::BtnTriggerDec) { + m_buttons[i].setDecEvent(event); + } + else if (trigger == CUIButton::BtnTriggerInc) { + m_buttons[i].setIncEvent(event); + } else { assert (trigger == CUIButton::BtnTriggerNone); } diff --git a/src/uibuttons.h b/src/uibuttons.h index 278244307..0621e3092 100644 --- a/src/uibuttons.h +++ b/src/uibuttons.h @@ -41,7 +41,9 @@ class CUIButton BtnTriggerNone = 0, BtnTriggerClick = 1, BtnTriggerDoubleClick = 2, - BtnTriggerLongPress = 3 + BtnTriggerLongPress = 3, + BtnTriggerDec = 4, + BtnTriggerInc = 5, }; enum BtnEvent @@ -65,11 +67,13 @@ class CUIButton ~CUIButton (void); void reset (void); - boolean Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout); + boolean Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout, unsigned MIDIRelativeDebounceTime); void setClickEvent(BtnEvent clickEvent); void setDoubleClickEvent(BtnEvent doubleClickEvent); void setLongPressEvent(BtnEvent longPressEvent); + void setDecEvent(BtnEvent decEvent); + void setIncEvent(BtnEvent incEvent); unsigned getPinNumber(void); @@ -100,11 +104,17 @@ class CUIButton BtnEvent m_doubleClickEvent; // Event to fire on long press BtnEvent m_longPressEvent; - + // Event to fire on dec + BtnEvent m_decEvent; + // Event to fire on inc + BtnEvent m_incEvent; + // Timeout for double click in tenths of a millisecond unsigned m_doubleClickTimeout; // Timeout for long press in tenths of a millisecond unsigned m_longPressTimeout; + // Debounce time for MIDI Relative messages in tenths of a millisecond + unsigned m_MIDIRelativeDebounceTime; }; class CUIButtons @@ -132,11 +142,6 @@ class CUIButtons // Array of normal GPIO buttons and "MIDI buttons" CUIButton m_buttons[MAX_BUTTONS]; - // Timeout for double click in tenths of a millisecond - unsigned m_doubleClickTimeout; - // Timeout for long press in tenths of a millisecond - unsigned m_longPressTimeout; - // Configuration for buttons unsigned m_prevPin; CUIButton::BtnTrigger m_prevAction; @@ -165,18 +170,30 @@ class CUIButtons // MIDI button configuration unsigned m_notesMidi; + unsigned m_prevMidi; + CUIButton::BtnTrigger m_prevMidiAction; unsigned m_nextMidi; + CUIButton::BtnTrigger m_nextMidiAction; unsigned m_backMidi; + CUIButton::BtnTrigger m_backMidiAction; unsigned m_selectMidi; + CUIButton::BtnTrigger m_selectMidiAction; unsigned m_homeMidi; + CUIButton::BtnTrigger m_homeMidiAction; unsigned m_pgmUpMidi; + CUIButton::BtnTrigger m_pgmUpMidiAction; unsigned m_pgmDownMidi; + CUIButton::BtnTrigger m_pgmDownMidiAction; unsigned m_BankUpMidi; + CUIButton::BtnTrigger m_BankUpMidiAction; unsigned m_BankDownMidi; + CUIButton::BtnTrigger m_BankDownMidiAction; unsigned m_TGUpMidi; + CUIButton::BtnTrigger m_TGUpMidiAction; unsigned m_TGDownMidi; + CUIButton::BtnTrigger m_TGDownMidiAction; BtnEventHandler *m_eventHandler; void *m_eventParam; diff --git a/src/uimenu.cpp b/src/uimenu.cpp index e8342c8ab..55e56f3b3 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -28,10 +28,10 @@ #include "config.h" #include #include +#include #include #include -using namespace std; LOGMODULE ("uimenu"); const CUIMenu::TMenuItem CUIMenu::s_MenuRoot[] = @@ -63,63 +63,83 @@ const CUIMenu::TMenuItem CUIMenu::s_MainMenu[] = {"TG16", MenuHandler, s_TGMenu, 15}, #endif #endif + {"Status", MenuHandler, s_StatusMenu}, + {"Mixer", MenuHandler, s_MixerMenu}, +#ifdef ARM_ALLOW_MULTI_CORE {"Effects", MenuHandler, s_EffectsMenu}, - {"Master Volume", EditMasterVolume, 0, 0}, +#endif {"Performance", MenuHandler, s_PerformanceMenu}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] = { - {"Voice", EditProgramNumber}, + {"Voice", EditProgramNumber, 0, CMiniDexed::TGParameterProgram, "Voice"}, {"Bank", EditVoiceBankNumber}, - {"Volume", EditTGParameter, 0, CMiniDexed::TGParameterVolume}, + {"Volume", EditTGParameter, 0, CMiniDexed::TGParameterVolume, "Vol"}, #ifdef ARM_ALLOW_MULTI_CORE - {"Pan", EditTGParameter, 0, CMiniDexed::TGParameterPan}, - {"Reverb-Send", EditTGParameter, 0, CMiniDexed::TGParameterReverbSend}, + {"Pan", EditTGParameter, 0, CMiniDexed::TGParameterPan, "Pan"}, + {"FX1-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX1Send, "FX1"}, + {"FX2-Send", EditTGParameter, 0, CMiniDexed::TGParameterFX2Send, "FX2"}, #endif - {"Detune", EditTGParameter, 0, CMiniDexed::TGParameterMasterTune}, - {"Cutoff", EditTGParameter, 0, CMiniDexed::TGParameterCutoff}, - {"Resonance", EditTGParameter, 0, CMiniDexed::TGParameterResonance}, + {"Detune", EditTGParameter, 0, CMiniDexed::TGParameterMasterTune, "DeT"}, + {"Cutoff", EditTGParameter, 0, CMiniDexed::TGParameterCutoff, "Cut"}, + {"Resonance", EditTGParameter, 0, CMiniDexed::TGParameterResonance, "Res"}, {"Pitch Bend", MenuHandler, s_EditPitchBendMenu}, {"Portamento", MenuHandler, s_EditPortamentoMenu}, - {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode}, + {"Note Limit", MenuHandler, s_EditNoteLimitMenu}, + {"Poly/Mono", EditTGParameter, 0, CMiniDexed::TGParameterMonoMode, "P/M"}, + {"TG-Link", EditTGParameter, 0, CMiniDexed::TGParameterTGLink}, + {"Enabled", EditTGParameter, 0, CMiniDexed::TGParameterEnabled}, {"Modulation", MenuHandler, s_ModulationMenu}, - {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel}, + {"Channel", EditTGParameter, 0, CMiniDexed::TGParameterMIDIChannel, "Chan"}, + {"EQ", MenuHandler, s_EQMenu}, + {"Compressor", MenuHandler, s_EditCompressorMenu}, {"Edit Voice", MenuHandler, s_EditVoiceMenu}, {0} }; -const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = +const CUIMenu::TMenuItem CUIMenu::s_EditCompressorMenu[] = { - {"Compress", EditGlobalParameter, 0, CMiniDexed::ParameterCompressorEnable}, -#ifdef ARM_ALLOW_MULTI_CORE - {"Reverb", MenuHandler, s_ReverbMenu}, -#endif + {"Enable", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorEnable, "CEn"}, + {"Pre Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorPreGain, "CPg"}, + {"Threshold", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorThresh, "CTh"}, + {"Ratio", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRatio, "CRa"}, + {"Attack", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorAttack, "CAt"}, + {"Release", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorRelease, "CRe"}, + {"Makeup Gain", EditTGParameter2, 0, CMiniDexed::TGParameterCompressorMakeupGain, "CPm"}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_EditPitchBendMenu[] = { - {"Bend Range", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendRange}, - {"Bend Step", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendStep}, + {"Bend Range", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendRange, "PiBR"}, + {"Bend Step", EditTGParameter2, 0, CMiniDexed::TGParameterPitchBendStep, "PiBS"}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_EditPortamentoMenu[] = { - {"Mode", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoMode}, - {"Glissando", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoGlissando}, - {"Time", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoTime}, + {"Mode", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoMode, "PorM"}, + {"Glissando", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoGlissando, "PorG"}, + {"Time", EditTGParameter2, 0, CMiniDexed::TGParameterPortamentoTime, "PorT"}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_EditNoteLimitMenu[] = +{ + {"Limit Low", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitLow, .OnSelect=InputKeyDown}, + {"Limit High", EditTGParameter2, 0, CMiniDexed::TGParameterNoteLimitHigh, .OnSelect=InputKeyDown}, + {"Shift", EditTGParameter2, 0, CMiniDexed::TGParameterNoteShift, .OnSelect=InputShiftKeyDown}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_ModulationMenu[] = { - {"Mod. Wheel", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterMWRange}, - {"Foot Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterFCRange}, - {"Breath Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterBCRange}, - {"Aftertouch", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterATRange}, + {"Mod. Wheel", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterMWRange, "MWR"}, + {"Foot Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterFCRange, "FCR"}, + {"Breath Control", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterBCRange, "BCR"}, + {"Aftertouch", MenuHandler, s_ModulationMenuParameters, CMiniDexed::TGParameterATRange, "ATR"}, {0} }; @@ -132,17 +152,229 @@ const CUIMenu::TMenuItem CUIMenu::s_ModulationMenuParameters[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_EQMenu[] = +{ + {"Low Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQLow, "TQL"}, + {"Mid Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQMid, "TQM"}, + {"High Level", EditTGParameter2, 0, CMiniDexed::TGParameterEQHigh, "TQH"}, + {"Gain", EditTGParameter2, 0, CMiniDexed::TGParameterEQGain, "TQG"}, + {"Low-Mid Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQLowMidFreq, "TQLM"}, + {"Mid-High Freq", EditTGParameter2, 0, CMiniDexed::TGParameterEQMidHighFreq, "TQMH"}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_MixerMenu[] = +{ + {"Master Volume", EditGlobalParameter, 0, CMiniDexed::ParameterMasterVolume}, +#ifdef ARM_ALLOW_MULTI_CORE + {"Dry Level", EditGlobalParameter, 0, CMiniDexed::ParameterMixerDryLevel}, + {"FX1 Return", EditFXParameterG, 0, FX::FXParameterReturnLevel, .Parameter2=0}, + {"FX2 Return", EditFXParameterG, 0, FX::FXParameterReturnLevel, .Parameter2=1}, +#endif + {0} +}; + #ifdef ARM_ALLOW_MULTI_CORE -const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] = +const CUIMenu::TMenuItem CUIMenu::s_EffectsMenu[] = +{ + {"SendFX1", MenuHandler, s_SendFXMenu, 0}, + {"SendFX2", MenuHandler, s_SendFXMenu, 1}, + {"MasterFX", MenuHandler, s_MasterFXMenu, CConfig::MasterFX}, + {"Bypass", EditGlobalParameter, 0, CMiniDexed::ParameterFXBypass}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_SendFXMenu[] = +{ + {"Slot1", MenuHandler, s_FXListMenu, FX::FXParameterSlot0, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot2", MenuHandler, s_FXListMenu, FX::FXParameterSlot1, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot3", MenuHandler, s_FXListMenu, FX::FXParameterSlot2, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Return Level", EditFXParameter2, 0, FX::FXParameterReturnLevel}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterBypass}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_MasterFXMenu[] = +{ + {"Slot1", MenuHandler, s_FXListMenu, FX::FXParameterSlot0, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot2", MenuHandler, s_FXListMenu, FX::FXParameterSlot1, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Slot3", MenuHandler, s_FXListMenu, FX::FXParameterSlot2, .OnSelect=SelectCurrentEffect, .StepDown=StepDownEffect, .StepUp=StepUpEffect}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterBypass}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_FXListMenu[] = +{ + {"None"}, + {"YKChorus", MenuHandler, s_YKChorusMenu}, + {"DreamDelay", MenuHandler, s_DreamDelayMenu}, + {"PlateReverb", MenuHandler, s_PlateReverbMenu}, + {"CloudSeed2", MenuHandler, s_CloudSeed2Menu}, + {"Compressor", MenuHandler, s_CompressorMenu}, + {"EQ", MenuHandler, s_FXEQMenu}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_YKChorusMenu[] = +{ + {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterYKChorusMix}, + {"Enable I", EditFXParameter2, 0, FX::FXParameterYKChorusEnable1}, + {"Enable II", EditFXParameter2, 0, FX::FXParameterYKChorusEnable2}, + {"LFO Rate I", EditFXParameter2, 0, FX::FXParameterYKChorusLFORate1}, + {"LFO Rate II", EditFXParameter2, 0, FX::FXParameterYKChorusLFORate2}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterYKChorusBypass}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_DreamDelayMenu[] = +{ + {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterDreamDelayMix}, + {"Mode", EditFXParameter2, 0, FX::FXParameterDreamDelayMode}, + {"Time", EditFXParameter2, 0, FX::FXParameterDreamDelayTime}, + {"Time Left", EditFXParameter2, 0, FX::FXParameterDreamDelayTimeL}, + {"Time Right", EditFXParameter2, 0, FX::FXParameterDreamDelayTimeR}, + {"Tempo", EditFXParameter2, 0, FX::FXParameterDreamDelayTempo}, + {"Feedback", EditFXParameter2, 0, FX::FXParameterDreamDelayFeedback}, + {"HighCut", EditFXParameter2, 0, FX::FXParameterDreamDelayHighCut}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterDreamDelayBypass}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_PlateReverbMenu[] = +{ + {"Mix Dry:Wet", EditFXParameter2, 0, FX::FXParameterPlateReverbMix, "RvMx"}, + {"Size", EditFXParameter2, 0, FX::FXParameterPlateReverbSize, "RvS"}, + {"High damp", EditFXParameter2, 0, FX::FXParameterPlateReverbHighDamp, "RvHD"}, + {"Low damp", EditFXParameter2, 0, FX::FXParameterPlateReverbLowDamp, "RvLD"}, + {"Low pass", EditFXParameter2, 0, FX::FXParameterPlateReverbLowPass, "RvLP"}, + {"Diffusion", EditFXParameter2, 0, FX::FXParameterPlateReverbDiffusion, "RvDi"}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterPlateReverbBypass, "RvBP"}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2Menu[] = +{ + {"Load Preset", EditFXParameter2, 0, FX::FXParameterCloudSeed2Preset}, + {"Dry Out", EditFXParameter2, 0, FX::FXParameterCloudSeed2DryOut}, + {"Early Out", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyOut}, + {"Late Out", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateOut}, + {"Early FB", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseFeedback}, + {"Late FB", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseFeedback}, + {"Tap Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapDecay}, + {"Late Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineDecay}, + {"Late Lines", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineCount}, + {"Input", MenuHandler, s_CloudSeed2InputMenu}, + {"Multitap Delay", MenuHandler, s_CloudSeed2MultitapMenu}, + {"Early Diffusion", MenuHandler, s_CloudSeed2EarlyDiffusionMenu}, + {"Late Diffusion", MenuHandler, s_CloudSeed2LateDiffusionMenu}, + {"Late Lines", MenuHandler, s_CloudSeed2LateLineMenu}, + {"Low Shelf", MenuHandler, s_CloudSeed2LowShelfMenu}, + {"High Shelf", MenuHandler, s_CloudSeed2HighShelfMenu}, + {"Low Pass", MenuHandler, s_CloudSeed2LowPassMenu}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterCloudSeed2Bypass}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2InputMenu[] = +{ + {"Interpolation", EditFXParameter2, 0, FX::FXParameterCloudSeed2Interpolation}, + {"L/R Input Mix", EditFXParameter2, 0, FX::FXParameterCloudSeed2InputMix}, + {"High Cut Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2HighCutEnabled}, + {"High Cut", EditFXParameter2, 0, FX::FXParameterCloudSeed2HighCut}, + {"Low Cut Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2LowCutEnabled}, + {"Low Cut", EditFXParameter2, 0, FX::FXParameterCloudSeed2LowCut}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2MultitapMenu[] = +{ + {"Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapEnabled}, + {"Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapCount}, + {"Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapDecay}, + {"Predelay", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapPredelay}, + {"Length", EditFXParameter2, 0, FX::FXParameterCloudSeed2TapLength}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2EarlyDiffusionMenu[] = +{ + {"Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseEnabled}, + {"Stage Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseCount}, + {"Delay", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseDelay}, + {"Feedback", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseFeedback}, + {"Mod Amount", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseModAmount}, + {"Mod Rate", EditFXParameter2, 0, FX::FXParameterCloudSeed2EarlyDiffuseModRate}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LateDiffusionMenu[] = +{ + {"Enabled", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseEnabled}, + {"Stage Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseCount}, + {"Delay", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseDelay}, + {"Feedback", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseFeedback}, + {"Mod Amount", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseModAmount}, + {"Mod Rate", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateDiffuseModRate}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LateLineMenu[] = +{ + {"Mode", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateMode}, + {"Count", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineCount}, + {"Size", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineSize}, + {"Decay", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineDecay}, + {"Mod Amt", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineModAmount}, + {"Mod Rate", EditFXParameter2, 0, FX::FXParameterCloudSeed2LateLineModRate}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LowShelfMenu[] = +{ + {"Enable", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowShelfEnabled}, + {"Freq", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowFreq}, + {"Gain", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowGain}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2HighShelfMenu[] = +{ + {"Enable", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqHighShelfEnabled}, + {"Freq", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqHighFreq}, + {"Gain", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqHighGain}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CloudSeed2LowPassMenu[] = { - {"Enable", EditGlobalParameter, 0, CMiniDexed::ParameterReverbEnable}, - {"Size", EditGlobalParameter, 0, CMiniDexed::ParameterReverbSize}, - {"High damp", EditGlobalParameter, 0, CMiniDexed::ParameterReverbHighDamp}, - {"Low damp", EditGlobalParameter, 0, CMiniDexed::ParameterReverbLowDamp}, - {"Low pass", EditGlobalParameter, 0, CMiniDexed::ParameterReverbLowPass}, - {"Diffusion", EditGlobalParameter, 0, CMiniDexed::ParameterReverbDiffusion}, - {"Level", EditGlobalParameter, 0, CMiniDexed::ParameterReverbLevel}, + {"Enable", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqLowpassEnabled}, + {"Cutoff", EditFXParameter2, 0, FX::FXParameterCloudSeed2EqCutoff}, + {0}, +}; + +const CUIMenu::TMenuItem CUIMenu::s_CompressorMenu[] = +{ + {"Pre Gain", EditFXParameter2, 0, FX::FXParameterCompressorPreGain}, + {"Threshold", EditFXParameter2, 0, FX::FXParameterCompressorThresh}, + {"Ratio", EditFXParameter2, 0, FX::FXParameterCompressorRatio}, + {"Attack", EditFXParameter2, 0, FX::FXParameterCompressorAttack}, + {"Release", EditFXParameter2, 0, FX::FXParameterCompressorRelease}, + {"Makeup Gain", EditFXParameter2, 0, FX::FXParameterCompressorMakeupGain}, + {"HPFilter", EditFXParameter2, 0, FX::FXParameterCompressorHPFilterEnable}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterCompressorBypass}, + {0} +}; + +const CUIMenu::TMenuItem CUIMenu::s_FXEQMenu[] = +{ + {"Low Level", EditFXParameter2, 0, FX::FXParameterEQLow}, + {"Mid Level", EditFXParameter2, 0, FX::FXParameterEQMid}, + {"High Level", EditFXParameter2, 0, FX::FXParameterEQHigh}, + {"Gain", EditFXParameter2, 0, FX::FXParameterEQGain}, + {"Low-Mid Freq", EditFXParameter2, 0, FX::FXParameterEQLowMidFreq}, + {"Mid-High Freq", EditFXParameter2, 0, FX::FXParameterEQMidHighFreq}, + {"Bypass", EditFXParameter2, 0, FX::FXParameterEQBypass}, {0} }; @@ -157,53 +389,53 @@ const CUIMenu::TMenuItem CUIMenu::s_EditVoiceMenu[] = {"OP4", MenuHandler, s_OperatorMenu, 3}, {"OP5", MenuHandler, s_OperatorMenu, 4}, {"OP6", MenuHandler, s_OperatorMenu, 5}, - {"Algorithm", EditVoiceParameter, 0, DEXED_ALGORITHM}, - {"Feedback", EditVoiceParameter, 0, DEXED_FEEDBACK}, - {"P EG Rate 1", EditVoiceParameter, 0, DEXED_PITCH_EG_R1}, - {"P EG Rate 2", EditVoiceParameter, 0, DEXED_PITCH_EG_R2}, - {"P EG Rate 3", EditVoiceParameter, 0, DEXED_PITCH_EG_R3}, - {"P EG Rate 4", EditVoiceParameter, 0, DEXED_PITCH_EG_R4}, - {"P EG Level 1",EditVoiceParameter, 0, DEXED_PITCH_EG_L1}, - {"P EG Level 2",EditVoiceParameter, 0, DEXED_PITCH_EG_L2}, - {"P EG Level 3",EditVoiceParameter, 0, DEXED_PITCH_EG_L3}, - {"P EG Level 4",EditVoiceParameter, 0, DEXED_PITCH_EG_L4}, - {"Osc Key Sync",EditVoiceParameter, 0, DEXED_OSC_KEY_SYNC}, - {"LFO Speed", EditVoiceParameter, 0, DEXED_LFO_SPEED}, - {"LFO Delay", EditVoiceParameter, 0, DEXED_LFO_DELAY}, - {"LFO PMD", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_DEP}, - {"LFO AMD", EditVoiceParameter, 0, DEXED_LFO_AMP_MOD_DEP}, - {"LFO Sync", EditVoiceParameter, 0, DEXED_LFO_SYNC}, - {"LFO Wave", EditVoiceParameter, 0, DEXED_LFO_WAVE}, - {"P Mod Sens.", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_SENS}, - {"Transpose", EditVoiceParameter, 0, DEXED_TRANSPOSE}, + {"Algorithm", EditVoiceParameter, 0, DEXED_ALGORITHM, "Alg"}, + {"Feedback", EditVoiceParameter, 0, DEXED_FEEDBACK, "FB"}, + {"P EG Rate 1", EditVoiceParameter, 0, DEXED_PITCH_EG_R1, "PR1"}, + {"P EG Rate 2", EditVoiceParameter, 0, DEXED_PITCH_EG_R2, "PR2"}, + {"P EG Rate 3", EditVoiceParameter, 0, DEXED_PITCH_EG_R3, "PR3"}, + {"P EG Rate 4", EditVoiceParameter, 0, DEXED_PITCH_EG_R4, "PR4"}, + {"P EG Level 1",EditVoiceParameter, 0, DEXED_PITCH_EG_L1, "PL1"}, + {"P EG Level 2",EditVoiceParameter, 0, DEXED_PITCH_EG_L2, "PL2"}, + {"P EG Level 3",EditVoiceParameter, 0, DEXED_PITCH_EG_L3, "PL3"}, + {"P EG Level 4",EditVoiceParameter, 0, DEXED_PITCH_EG_L4, "PL4"}, + {"Osc Key Sync",EditVoiceParameter, 0, DEXED_OSC_KEY_SYNC, "OKS"}, + {"LFO Speed", EditVoiceParameter, 0, DEXED_LFO_SPEED, "LSP"}, + {"LFO Delay", EditVoiceParameter, 0, DEXED_LFO_DELAY, "LDE"}, + {"LFO PMD", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_DEP, "LPMD"}, + {"LFO AMD", EditVoiceParameter, 0, DEXED_LFO_AMP_MOD_DEP, "LAMD"}, + {"LFO Sync", EditVoiceParameter, 0, DEXED_LFO_SYNC, "LSYN"}, + {"LFO Wave", EditVoiceParameter, 0, DEXED_LFO_WAVE, "LWAV"}, + {"P Mod Sens.", EditVoiceParameter, 0, DEXED_LFO_PITCH_MOD_SENS, "LPMS"}, + {"Transpose", EditVoiceParameter, 0, DEXED_TRANSPOSE, "TRP"}, {"Name", InputTxt,0 , 3}, {0} }; const CUIMenu::TMenuItem CUIMenu::s_OperatorMenu[] = { - {"Output Level",EditOPParameter, 0, DEXED_OP_OUTPUT_LEV}, - {"Freq Coarse", EditOPParameter, 0, DEXED_OP_FREQ_COARSE}, - {"Freq Fine", EditOPParameter, 0, DEXED_OP_FREQ_FINE}, - {"Osc Detune", EditOPParameter, 0, DEXED_OP_OSC_DETUNE}, - {"Osc Mode", EditOPParameter, 0, DEXED_OP_OSC_MODE}, - {"EG Rate 1", EditOPParameter, 0, DEXED_OP_EG_R1}, - {"EG Rate 2", EditOPParameter, 0, DEXED_OP_EG_R2}, - {"EG Rate 3", EditOPParameter, 0, DEXED_OP_EG_R3}, - {"EG Rate 4", EditOPParameter, 0, DEXED_OP_EG_R4}, - {"EG Level 1", EditOPParameter, 0, DEXED_OP_EG_L1}, - {"EG Level 2", EditOPParameter, 0, DEXED_OP_EG_L2}, - {"EG Level 3", EditOPParameter, 0, DEXED_OP_EG_L3}, - {"EG Level 4", EditOPParameter, 0, DEXED_OP_EG_L4}, - {"Break Point", EditOPParameter, 0, DEXED_OP_LEV_SCL_BRK_PT}, - {"L Key Depth", EditOPParameter, 0, DEXED_OP_SCL_LEFT_DEPTH}, - {"R Key Depth", EditOPParameter, 0, DEXED_OP_SCL_RGHT_DEPTH}, - {"L Key Scale", EditOPParameter, 0, DEXED_OP_SCL_LEFT_CURVE}, - {"R Key Scale", EditOPParameter, 0, DEXED_OP_SCL_RGHT_CURVE}, - {"Rate Scaling",EditOPParameter, 0, DEXED_OP_OSC_RATE_SCALE}, - {"A Mod Sens.", EditOPParameter, 0, DEXED_OP_AMP_MOD_SENS}, - {"K Vel. Sens.",EditOPParameter, 0, DEXED_OP_KEY_VEL_SENS}, - {"Enable", EditOPParameter, 0, DEXED_OP_ENABLE}, + {"Output Level",EditOPParameter, 0, DEXED_OP_OUTPUT_LEV, "OutL"}, + {"Freq Coarse", EditOPParameter, 0, DEXED_OP_FREQ_COARSE, "FrC"}, + {"Freq Fine", EditOPParameter, 0, DEXED_OP_FREQ_FINE, "FrF"}, + {"Osc Detune", EditOPParameter, 0, DEXED_OP_OSC_DETUNE, "OsDT"}, + {"Osc Mode", EditOPParameter, 0, DEXED_OP_OSC_MODE, "OsM"}, + {"EG Rate 1", EditOPParameter, 0, DEXED_OP_EG_R1, "R1"}, + {"EG Rate 2", EditOPParameter, 0, DEXED_OP_EG_R2, "R2"}, + {"EG Rate 3", EditOPParameter, 0, DEXED_OP_EG_R3, "R3"}, + {"EG Rate 4", EditOPParameter, 0, DEXED_OP_EG_R4, "R4"}, + {"EG Level 1", EditOPParameter, 0, DEXED_OP_EG_L1, "L1"}, + {"EG Level 2", EditOPParameter, 0, DEXED_OP_EG_L2, "L2"}, + {"EG Level 3", EditOPParameter, 0, DEXED_OP_EG_L3, "L3"}, + {"EG Level 4", EditOPParameter, 0, DEXED_OP_EG_L4, "L4"}, + {"Break Point", EditOPParameter, 0, DEXED_OP_LEV_SCL_BRK_PT, "BP"}, + {"L Key Depth", EditOPParameter, 0, DEXED_OP_SCL_LEFT_DEPTH, "LDep"}, + {"R Key Depth", EditOPParameter, 0, DEXED_OP_SCL_RGHT_DEPTH, "RDep"}, + {"L Key Scale", EditOPParameter, 0, DEXED_OP_SCL_LEFT_CURVE, "LSca"}, + {"R Key Scale", EditOPParameter, 0, DEXED_OP_SCL_RGHT_CURVE, "RSca"}, + {"Rate Scaling",EditOPParameter, 0, DEXED_OP_OSC_RATE_SCALE, "RS"}, + {"A Mod Sens.", EditOPParameter, 0, DEXED_OP_AMP_MOD_SENS, "AMS"}, + {"K Vel. Sens.",EditOPParameter, 0, DEXED_OP_KEY_VEL_SENS, "KVS"}, + {"Enable", EditOPParameter, 0, DEXED_OP_ENABLE, "OPEn"}, {0} }; @@ -216,22 +448,17 @@ const CUIMenu::TMenuItem CUIMenu::s_SaveMenu[] = }; // must match CMiniDexed::TParameter -const CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = -{ - {0, 1, 1, ToOnOff}, // ParameterCompessorEnable - {0, 1, 1, ToOnOff}, // ParameterReverbEnable - {0, 99, 1}, // ParameterReverbSize - {0, 99, 1}, // ParameterReverbHighDamp - {0, 99, 1}, // ParameterReverbLowDamp - {0, 99, 1}, // ParameterReverbLowPass - {0, 99, 1}, // ParameterReverbDiffusion - {0, 99, 1}, // ParameterReverbLevel +CUIMenu::TParameter CUIMenu::s_GlobalParameter[CMiniDexed::ParameterUnknown] = +{ {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // ParameterPerformanceSelectChannel - {0, NUM_PERFORMANCE_BANKS, 1} // ParameterPerformanceBank + {0, NUM_PERFORMANCE_BANKS, 1}, // ParameterPerformanceBank + {0, 127, 8, ToVolume}, // ParameterMasterVolume + {0, 99, 1}, // ParameterMixerDryLevel + {0, 1, 1, ToOnOff}, // ParameterFXBypass }; // must match CMiniDexed::TTGParameter -const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = +CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] = { {0, CSysExFileLoader::MaxVoiceBankID, 1}, // TGParameterVoiceBank {0, 0, 0}, // TGParameterVoiceBankMSB (not used in menus) @@ -243,13 +470,19 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] {0, 99, 1}, // TGParameterCutoff {0, 99, 1}, // TGParameterResonance {0, CMIDIDevice::ChannelUnknown-1, 1, ToMIDIChannel}, // TGParameterMIDIChannel - {0, 99, 1}, // TGParameterReverbSend + {0, 99, 1}, // TGParameterFX1Send + {0, 99, 1}, // TGParameterFX2Send {0, 12, 1}, // TGParameterPitchBendRange {0, 12, 1}, // TGParameterPitchBendStep {0, 1, 1, ToPortaMode}, // TGParameterPortamentoMode {0, 1, 1, ToPortaGlissando}, // TGParameterPortamentoGlissando {0, 99, 1}, // TGParameterPortamentoTime + {0, 127, 1, ToMIDINote}, // TGParameterNoteLimitLow + {0, 127, 1, ToMIDINote}, // TGParameterNoteLimitHigh + {-24, 24, 1, ToMIDINoteShift}, // TGParameterNoteShift {0, 1, 1, ToPolyMono}, // TGParameterMonoMode + {0, 4, 1, ToTGLinkName}, // TGParameterTGLink + {0, 1, 1, ToOnOff}, // TGParameterEnabled {0, 99, 1}, //MW Range {0, 1, 1, ToOnOff}, //MW Pitch {0, 1, 1, ToOnOff}, //MW Amp @@ -265,7 +498,20 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown] {0, 99, 1}, //AT Range {0, 1, 1, ToOnOff}, //AT Pitch {0, 1, 1, ToOnOff}, //AT Amp - {0, 1, 1, ToOnOff} //AT EGBias + {0, 1, 1, ToOnOff}, //AT EGBias + {0, 1, 1, ToOnOff}, // TGParameterCompressorEnable + {-20, 20, 1, TodB}, // TGParameterCompressorPreGain + {-60, 0, 1, TodBFS}, // TGParameterCompressorThresh + {1, CMiniDexed::CompressorRatioInf, 1, ToRatio}, // TGParameterCompressorRatio + {0, 1000, 5, ToMillisec}, // TGParameterCompressorAttack + {0, 2000, 5, ToMillisec}, // TGParameterCompressorRelease + {-20, 20, 1, TodB}, // TGParameterCompressorMakeupGain + {-24, 24, 1, TodB}, // TGParameterEQLow + {-24, 24, 1, TodB}, // TGParameterEQMid + {-24, 24, 1, TodB}, // TGParameterEQHigh + {-24, 24, 1, TodB}, // TGParameterEQGain + {0, 46, 1, ToHz}, // TGParameterEQLowMidFreq + {28, 59, 1, ToHz}, // TGParameterEQMidHighFreq }; // must match DexedVoiceParameters in Synth_Dexed @@ -333,7 +579,32 @@ const char CUIMenu::s_NoteName[100][5] = "A7", "A#7", "B7", "C8" }; +const char CUIMenu::s_MIDINoteName[128][9] = +{ +"0 C-2", "1 C#-2", "2 D-2", "3 D#-2", "4 E-2", "5 F-2", "6 F#-2", "7 G-2", "8 G#-2", "9 A-2", "10 A#-2", "11 B-2", +"12 C-1", "13 C#-1", "14 D-1", "15 D#-1", "16 E-1", "17 F-1", "18 F#-1", "19 G-1", "20 G#-1", "21 A-1", "22 A#-1", "23 B-1", +"24 C0", "25 C#0", "26 D0", "27 D#0", "28 E0", "29 F0", "30 F#0", "31 G0", "32 G#0", "33 A0", "34 A#0", "35 B0", +"36 C1", "37 C#1", "38 D1", "39 D#1", "40 E1", "41 F1", "42 F#1", "43 G1", "44 G#1", "45 A1", "46 A#1", "47 B1", +"48 C2", "49 C#2", "50 D2", "51 D#2", "52 E2", "53 F2", "54 F#2", "55 G2", "56 G#2", "57 A2", "58 A#2", "59 B2", +"60 C3", "61 C#3", "62 D3", "63 D#3", "64 E3", "65 F3", "66 F#3", "67 G3", "68 G#3", "69 A3", "70 A#3", "71 B3", +"72 C4", "73 C#4", "74 D4", "75 D#4", "76 E4", "77 F4", "78 F#4", "79 G4", "80 G#4", "81 A4", "82 A#4", "83 B4", +"84 C5", "85 C#5", "86 D5", "87 D#5", "88 E5", "89 F5", "90 F#5", "91 G5", "92 G#5", "93 A5", "94 A#5", "95 B5", +"96 C6", "97 C#6", "98 D6", "99 D#6", "100 E6", "101 F6", "102 F#6", "103 G6", "104 G#6", "105 A6", "106 A#6", "107 B6", +"108 C7", "109 C#7", "110 D7", "111 D#7", "112 E7", "113 F7", "114 F#7", "115 G7", "116 G#7", "117 A7", "118 A#7", "119 B7", +"120 C8", "121 C#8", "122 D8", "123 D#8", "124 E8", "125 F8", "126 F#8", "127 G8" +}; + +const char CUIMenu::s_MIDINoteShift[49][8] = +{ +"-24 C1", "-23 C#1", "-22 D1", "-21 D#1", "-20 E1", "-19 F1", "-18 F#1", "-17 G1", "-16 G#1", "-15 A1", "-14 A#1", "-13 B1", +"-12 C2", "-11 C#2", "-10 D2", "-9 D#2", "-8 E2", "-7 F2", "-6 F#2", "-5 G2", "-4 G#2", "-3 A2", "-2 A#2", "-1 B2", +"0 C3", "+1 C#3", "+2 D3", "+3 D#3", "+4 E3", "+5 F3", "+6 F#3", "+7 G3", "+8 G#3", "+9 A3", "+10 A#3", "+11 B3", +"+12 C4", "+13 C#4", "+14 D4", "+15 D#4", "+16 E4", "+17 F4", "+18 F#4", "+19 G4", "+20 G#4", "+21 A4", "+22 A#4", "+23 B4", +"+24 C5" +}; + static const unsigned NoteC3 = 39; +static const unsigned MIDINoteC3 = 60; const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = { @@ -345,6 +616,184 @@ const CUIMenu::TMenuItem CUIMenu::s_PerformanceMenu[] = {0} }; +const CUIMenu::TMenuItem CUIMenu::s_StatusMenu[] = +{ + {"CPU Temp", ShowCPUTemp, 0, 0, .ShowDirect=true}, + {"CPU Speed", ShowCPUSpeed, 0, 0, .ShowDirect=true}, + {"Net IP", ShowIPAddr, 0, 0, .ShowDirect=true}, + {"Version", ShowVersion, 0, 0, .ShowDirect=true}, + {0} +}; + +void CUIMenu::ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + CStatus *pStatus = CStatus::Get (); + + char info[17]; + snprintf(info, sizeof(info), "%d/%d C", pStatus->nCPUTemp.load(), pStatus->nCPUMaxTemp); + + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + info, + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); + + static TKernelTimerHandle timer = 0; + if (timer) CTimer::Get ()->CancelKernelTimer(timer); + timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); +} + +void CUIMenu::ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + CStatus *pStatus = CStatus::Get (); + + char info[17]; + snprintf(info, sizeof(info), "%d/%d MHz", pStatus->nCPUClockRate.load() / 1000000, pStatus->nCPUMaxClockRate / 1000000); + + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + info, + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); + + static TKernelTimerHandle timer = 0; + if (timer) CTimer::Get ()->CancelKernelTimer(timer); + timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); +} + +void CUIMenu::ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + CString IPString("-"); + const CIPAddress& IPAddr = pUIMenu->m_pMiniDexed->GetNetworkIPAddress(); + + if (IPAddr.IsSet()) + { + IPAddr.Format(&IPString); + } + + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + (const char*)IPString, + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); + + static TKernelTimerHandle timer = 0; + if (timer) CTimer::Get ()->CancelKernelTimer(timer); + timer = CTimer::Get ()->StartKernelTimer (MSEC2HZ (3000), TimerHandlerUpdate, 0, pUIMenu); +} + +void CUIMenu::ShowVersion (CUIMenu *pUIMenu, TMenuEvent Event) +{ + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + default: + return; + } + + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + VERSION, + pUIMenu->m_nCurrentSelection > 0, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name); +} + +const void CUIMenu::GetParameterInfo (CUIMenu::TCParameterInfo *pParam) +{ + static const CUIMenu::TMenuItem *globalSources[] = { +//#ifdef ARM_ALLOW_MULTI_CORE +// s_PlateReverbMenu, +// s_MasterEQMenu, +// s_MasterCompressorMenu, +//#endif + 0}; + static const CUIMenu::TMenuItem *tgSources[] = {s_TGMenu, s_EditPortamentoMenu, s_EditPitchBendMenu, s_ModulationMenu, s_EQMenu, s_EditCompressorMenu, 0}; + static const CUIMenu::TMenuItem *voiceSources[] = {s_EditVoiceMenu + 6, 0}; // skip Operators + static const CUIMenu::TMenuItem *opSources[] = {s_OperatorMenu, 0}; + const CUIMenu::TMenuItem **pSources = NULL; + const CUIMenu::TParameter *pInfo = NULL; + + switch (pParam->Type) + { + case ParameterGlobal: + pSources = globalSources; + pInfo = s_GlobalParameter; + break; + case ParameterTG: + pSources = tgSources; + pInfo = s_TGParameter; + break; + case ParameterVoice: + pSources = voiceSources; + pInfo = s_VoiceParameter; + break; + case ParameterOP: + pSources = opSources; + pInfo = s_OPParameter; + break; + default: + return; + } + + pParam->Min = pInfo[pParam->Parameter].Minimum; + pParam->Max = pInfo[pParam->Parameter].Maximum; + if (!pParam->ToString) + pParam->ToString = pInfo[pParam->Parameter].ToString; + + // There are some parameters without entry eg TGParameterMWRange + // skip them + if (pParam->Name && pParam->Short) + return; + + for (const CUIMenu::TMenuItem **source = pSources; *source; ++source) + for (const CUIMenu::TMenuItem *m = *source; m->Name; ++m) + if (m->Parameter == pParam->Parameter) + { + if (!pParam->Name) + pParam->Name = m->Name; + if (!pParam->Short) + pParam->Short = m->Short; + return; + } + + pParam->Type = ParameterNone; + pParam->Parameter = 0; +} + +const void CUIMenu::GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n) +{ + for (size_t i = 0; i < n; ++i) + GetParameterInfo(&pParamInfo[i]); +} CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) : m_pUI (pUI), @@ -378,6 +827,13 @@ CUIMenu::CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig) m_nMenuStackSelection[0] = 0; m_nMenuStackParameter[0] = 0; } + + if (m_pConfig->GetEncoderEnabled()) + { + s_GlobalParameter[CMiniDexed::ParameterMasterVolume].Increment = 1; + s_TGParameter[CMiniDexed::TGParameterVolume].Increment = 1; + s_TGParameter[CMiniDexed::TGParameterPan].Increment = 1; + } } void CUIMenu::EventHandler (TMenuEvent Event) @@ -444,7 +900,28 @@ void CUIMenu::EventHandler (TMenuEvent Event) break; default: - (*m_pParentMenu[m_nCurrentMenuItem].Handler) (this, Event); + if (m_pParentMenu[m_nCurrentMenuItem].Handler) + (*m_pParentMenu[m_nCurrentMenuItem].Handler) (this, Event); + break; + } + + switch (Event) + { + case MenuEventBack: + case MenuEventHome: + case MenuEventSelect: + if (m_pCurrentMenu == s_MainMenu) + m_pMiniDexed->UpdateDAWMenu (PageMain, 0, 0, 0); + //else if (m_pCurrentMenu == s_EffectsMenu) + // m_pMiniDexed->UpdateDAWMenu (PageEffect, 0, 0, 0); + else if (m_pCurrentMenu == s_TGMenu) + m_pMiniDexed->UpdateDAWMenu (PageTG, 0, 0, m_nCurrentParameter + 1); + else if (m_pCurrentMenu == s_EditVoiceMenu) + m_pMiniDexed->UpdateDAWMenu (PageVoice, 0, 0, m_nMenuStackParameter[m_nCurrentMenuDepth - 1] + 1); + else if (m_pCurrentMenu == s_OperatorMenu) + m_pMiniDexed->UpdateDAWMenu (PageOP, 0, m_nCurrentParameter, m_nMenuStackParameter[m_nCurrentMenuDepth - 2] + 1); + break; + default: break; } } @@ -458,6 +935,10 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) case MenuEventSelect: // push menu assert (pUIMenu->m_nCurrentMenuDepth < MaxMenuDepth); + + if (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].ShowDirect) + break; + pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth] = pUIMenu->m_pParentMenu; pUIMenu->m_MenuStackMenu[pUIMenu->m_nCurrentMenuDepth] = pUIMenu->m_pCurrentMenu; pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth] @@ -475,9 +956,18 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].MenuItem; pUIMenu->m_nCurrentMenuItem = pUIMenu->m_nCurrentSelection; pUIMenu->m_nCurrentSelection = 0; + + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect) + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect (pUIMenu, Event); break; case MenuEventStepDown: + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepDown) + { + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepDown (pUIMenu, Event); + break; + } + if (pUIMenu->m_nCurrentSelection == 0) { // If in main mennu, wrap around @@ -508,6 +998,12 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) break; case MenuEventStepUp: + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepUp) + { + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].StepUp (pUIMenu, Event); + break; + } + ++pUIMenu->m_nCurrentSelection; if (!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name) // more entries? { @@ -535,17 +1031,48 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) } break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->GlobalShortcutHandler (Event); + return; + default: return; } if (pUIMenu->m_pCurrentMenu) // if this is another menu? { + if (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].ShowDirect) + { + pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Handler(pUIMenu, MenuEventUpdate); + return; + } + bool bIsMainMenu = pUIMenu->m_pCurrentMenu == s_MainMenu; - pUIMenu->m_pUI->DisplayWrite ( - pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + bool bIsTGMenu = pUIMenu->m_pCurrentMenu == s_TGMenu; + + std::string menuName = pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name; + + if (bIsTGMenu) + { + int nTG = pUIMenu->m_nCurrentParameter; + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); + if (nTGLink) menuName += ToTGLinkName(nTGLink, 0); + } + + std::string selectionName = pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name; + + if (pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].MenuItem == s_TGMenu) + { + int nTG = pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Parameter; + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); + if (nTGLink) selectionName += ToTGLinkName(nTGLink, 0); + } + + pUIMenu->m_pMiniDexed->DisplayWrite ( + menuName.c_str(), "", - pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, + selectionName.c_str(), pUIMenu->m_nCurrentSelection > 0 || bIsMainMenu, !!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name || bIsMainMenu); } @@ -586,17 +1113,24 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetParameter (Param, nValue); break; + case MenuEventPressAndStepDown: + case MenuEventPressAndStepUp: + pUIMenu->GlobalShortcutHandler (Event); + return; + default: return; } - const char *pMenuName = + const char *pMenuName = pUIMenu->m_nCurrentMenuDepth == 1 ? "" : pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - string Value = GetGlobalValueString (Param, pUIMenu->m_pMiniDexed->GetParameter (Param)); + std::string Value = GetGlobalValueString (Param, + pUIMenu->m_pMiniDexed->GetParameter (Param), + pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pMiniDexed->DisplayWrite (pMenuName, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -607,6 +1141,7 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-1]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -635,13 +1170,14 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); - string Value = to_string (nValue+1) + "=" + std::string Value = std::to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetBankName (nValue); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > 0, nValue < (int) CSysExFileLoader::MaxVoiceBankID); @@ -652,6 +1188,7 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-1]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterProgram, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -694,7 +1231,7 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) // Skip empty voices. // Use same criteria in PgmUpDownHandler() too. - string voiceName = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); + std::string voiceName = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); if (voiceName == "EMPTY " || voiceName == " " || voiceName == "----------" @@ -709,26 +1246,22 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) } else { // Format: 000:000 TG1 (bank:voice padded, TGx right-aligned) int nBank = pUIMenu->m_pMiniDexed->GetTGParameter(CMiniDexed::TGParameterVoiceBank, nTG); - std::string left = "000"; - left += std::to_string(nBank+1); - left = left.substr(left.length()-3,3); - left += ":"; + std::string voice = "000"; + voice += std::to_string(nBank+1); + voice = voice.substr(voice.length()-3,3); + voice += ":"; std::string voiceNum = "000"; voiceNum += std::to_string(nValue+1); voiceNum = voiceNum.substr(voiceNum.length()-3,3); - left += voiceNum; + voice += voiceNum; - std::string tgLabel = "TG" + std::to_string(nTG+1); - unsigned lcdCols = pUIMenu->m_pConfig->GetLCDColumns(); - unsigned pad = 0; - if (lcdCols > left.length() + tgLabel.length()) - pad = lcdCols - (unsigned)(left.length() + tgLabel.length()); - std::string topLine = left + std::string(pad, ' ') + tgLabel; + std::string TG = "TG" + std::to_string(nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); std::string Value = pUIMenu->m_pMiniDexed->GetVoiceName (nTG); - pUIMenu->m_pUI->DisplayWrite (topLine.c_str(), - "", + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str(), + voice.c_str(), Value.c_str(), nValue > 0, nValue < (int) CSysExFileLoader::VoicesPerBank); } @@ -742,6 +1275,7 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) const TParameter &rParam = s_TGParameter[Param]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -776,12 +1310,20 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); + if (nTGLink && + Param != CMiniDexed::TGParameterTGLink && + Param != CMiniDexed::TGParameterPan && + Param != CMiniDexed::TGParameterMasterTune + ) + TG += ToTGLinkName(nTGLink, 0); - string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); + std::string Value = GetTGValueString (Param, + pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), + pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -796,6 +1338,7 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me const TParameter &rParam = s_TGParameter[Param]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -803,6 +1346,11 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me case MenuEventUpdateParameter: break; + case MenuEventSelect: + if (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect) + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].OnSelect(pUIMenu, Event); + break; + case MenuEventStepDown: nValue -= rParam.Increment; if (nValue < rParam.Minimum) @@ -830,16 +1378,118 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); - string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); + std::string Value = GetTGValueString (Param, + pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), + pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + Value.c_str (), + nValue > rParam.Minimum, nValue < rParam.Maximum); +} + +void CUIMenu::EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) +{ + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + + int nValue = pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX); + + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + case MenuEventStepDown: + nValue -= rParam.Increment; + if (nValue < rParam.Minimum) + { + nValue = rParam.Minimum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + case MenuEventStepUp: + nValue += rParam.Increment; + if (nValue > rParam.Maximum) + { + nValue = rParam.Maximum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + default: + return; + } + + std::string FX; + if (nFX == CConfig::MasterFX) FX = "MFX"; + else FX = std::string("FX") + std::to_string (nFX+1); + + std::string Value = GetFXValueString (Param, + pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), + pUIMenu->m_pConfig->GetLCDColumns() - 2); + + pUIMenu->m_pMiniDexed->DisplayWrite (FX.c_str (), + pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, + Value.c_str (), + nValue > rParam.Minimum, nValue < rParam.Maximum); +} + +void CUIMenu::EditFXParameterG (CUIMenu *pUIMenu, TMenuEvent Event) +{ + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + unsigned nFX = pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Parameter2; + + int nValue = pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX); + + switch (Event) + { + case MenuEventUpdate: + case MenuEventUpdateParameter: + break; + + case MenuEventStepDown: + nValue -= rParam.Increment; + if (nValue < rParam.Minimum) + { + nValue = rParam.Minimum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + case MenuEventStepUp: + nValue += rParam.Increment; + if (nValue > rParam.Maximum) + { + nValue = rParam.Maximum; + } + pUIMenu->m_pMiniDexed->SetFXParameter (Param, nValue, nFX); + break; + + default: + return; + } + + std::string FX; + if (nFX == CConfig::MasterFX) FX = "MFX"; + else FX = std::string("FX") + std::to_string (nFX+1); + + std::string Value = GetFXValueString (Param, + pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX), + pUIMenu->m_pConfig->GetLCDColumns() - 2); + + pUIMenu->m_pMiniDexed->DisplayWrite (FX.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); - } void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) @@ -850,6 +1500,7 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) const TParameter &rParam = s_VoiceParameter[nParam]; int nValue = pUIMenu->m_pMiniDexed->GetVoiceParameter (nParam, CMiniDexed::NoOP, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -884,12 +1535,13 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); - string Value = GetVoiceValueString (nParam, nValue); + std::string Value = GetVoiceValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -938,10 +1590,10 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string OP ("OP"); - OP += to_string (nOP+1); + std::string OP ("OP"); + OP += std::to_string (nOP+1); - string Value; + std::string Value; static const int FixedMultiplier[4] = {1, 10, 100, 1000}; if (nParam == DEXED_OP_FREQ_COARSE) @@ -955,14 +1607,14 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) } else { - Value = to_string (nValue); + Value = std::to_string (nValue); Value += ".00"; } } else { // Fixed - Value = to_string (FixedMultiplier[nValue % 4]); + Value = std::to_string (FixedMultiplier[nValue % 4]); } } else if (nParam == DEXED_OP_FREQ_FINE) @@ -990,10 +1642,10 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) } else { - Value = GetOPValueString (nParam, nValue); + Value = GetOPValueString (nParam, nValue, pUIMenu->m_pConfig->GetLCDColumns() - 2); } - pUIMenu->m_pUI->DisplayWrite (OP.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (OP.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -1012,7 +1664,7 @@ void CUIMenu::SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pMiniDexed->DisplayWrite (pMenuName, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, bOK ? "Completed" : "Error", false, false); @@ -1020,125 +1672,141 @@ void CUIMenu::SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event) CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandler, 0, pUIMenu); } -string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue) +std::string CUIMenu::GetGlobalValueString (unsigned nParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nParameter < sizeof CUIMenu::s_GlobalParameter / sizeof CUIMenu::s_GlobalParameter[0]); CUIMenu::TToString *pToString = CUIMenu::s_GlobalParameter[nParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue) +std::string CUIMenu::GetTGValueString (unsigned nTGParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nTGParameter < sizeof CUIMenu::s_TGParameter / sizeof CUIMenu::s_TGParameter[0]); CUIMenu::TToString *pToString = CUIMenu::s_TGParameter[nTGParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); + } + else + { + Result = std::to_string (nValue); + } + + return Result; +} + +std::string CUIMenu::GetFXValueString (unsigned nFXParameter, int nValue, int nWidth) +{ + std::string Result; + + assert (nFXParameter < FX::FXParameterUnknown); + + CUIMenu::TToString *pToString = FX::s_FXParameter[nFXParameter].ToString; + if (pToString) + { + Result = (*pToString) (nValue, nWidth); } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue) +std::string CUIMenu::GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nVoiceParameter < sizeof CUIMenu::s_VoiceParameter / sizeof CUIMenu::s_VoiceParameter[0]); CUIMenu::TToString *pToString = CUIMenu::s_VoiceParameter[nVoiceParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue) +std::string CUIMenu::GetOPValueString (unsigned nOPParameter, int nValue, int nWidth) { - string Result; + std::string Result; assert (nOPParameter < sizeof CUIMenu::s_OPParameter / sizeof CUIMenu::s_OPParameter[0]); CUIMenu::TToString *pToString = CUIMenu::s_OPParameter[nOPParameter].ToString; if (pToString) { - Result = (*pToString) (nValue); + Result = (*pToString) (nValue, nWidth); } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::ToVolume (int nValue) +std::string CUIMenu::ToVolume (int nValue, int nWidth) { - constexpr size_t NumSquares = 14; - char VolumeBar[NumSquares + 1]; - size_t filled = (nValue * NumSquares + 63) / 127; - for (size_t i = 0; i < NumSquares; ++i) { - VolumeBar[i] = (i < filled) ? (char)0xFF : '.'; - } - VolumeBar[NumSquares] = '\0'; - return VolumeBar; + char buf[nWidth + 1]; + unsigned nBarWidth = nWidth - 3; + unsigned nFillWidth = (nValue * nBarWidth + 63) / 127; + unsigned nDotWidth = nBarWidth - nFillWidth; + std::fill_n(buf, nFillWidth, 0xFF); + std::fill_n(buf + nFillWidth, nDotWidth, '.'); + snprintf(buf + nFillWidth + nDotWidth, 4, "%3d", nValue); + return buf; } -string CUIMenu::ToPan (int nValue) +std::string CUIMenu::ToPan (int nValue, int nWidth) { - assert (CConfig::LCDColumns == 16); - static const size_t MaxChars = CConfig::LCDColumns-3; - char PanMarker[MaxChars+1] = "......:......"; - unsigned nIndex = nValue * MaxChars / 127; - if (nIndex == MaxChars) - { - nIndex--; - } - PanMarker[nIndex] = '\xFF'; // 0xFF is the block character - - return PanMarker; + char buf[nWidth + 1]; + unsigned nBarWidth = nWidth - 3; + unsigned nIndex = std::min(nValue * nBarWidth / 127, nBarWidth - 1); + std::fill_n(buf, nBarWidth, '.'); + buf[nBarWidth / 2] = ':'; + buf[nIndex] = 0xFF; // 0xFF is the block character + snprintf(buf + nBarWidth, 4, "%3d", nValue); + return buf; } -string CUIMenu::ToMIDIChannel (int nValue) +std::string CUIMenu::ToMIDIChannel (int nValue, int nWidth) { switch (nValue) { case CMIDIDevice::OmniMode: return "Omni"; case CMIDIDevice::Disabled: return "Off"; - default: return to_string (nValue+1); + default: return std::to_string (nValue+1); } } -string CUIMenu::ToAlgorithm (int nValue) +std::string CUIMenu::ToAlgorithm (int nValue, int nWidth) { - return to_string (nValue + 1); + return std::to_string (nValue + 1); } -string CUIMenu::ToOnOff (int nValue) +std::string CUIMenu::ToOnOff (int nValue, int nWidth) { static const char *OnOff[] = {"Off", "On"}; @@ -1147,7 +1815,7 @@ string CUIMenu::ToOnOff (int nValue) return OnOff[nValue]; } -string CUIMenu::ToLFOWaveform (int nValue) +std::string CUIMenu::ToLFOWaveform (int nValue, int nWidth) { static const char *Waveform[] = {"Triangle", "Saw down", "Saw up", "Square", "Sine", "Sample/Hold"}; @@ -1157,7 +1825,7 @@ string CUIMenu::ToLFOWaveform (int nValue) return Waveform[nValue]; } -string CUIMenu::ToTransposeNote (int nValue) +std::string CUIMenu::ToTransposeNote (int nValue, int nWidth) { nValue += NoteC3 - 24; @@ -1166,14 +1834,28 @@ string CUIMenu::ToTransposeNote (int nValue) return s_NoteName[nValue]; } -string CUIMenu::ToBreakpointNote (int nValue) +std::string CUIMenu::ToBreakpointNote (int nValue, int nWidth) { assert ((unsigned) nValue < sizeof s_NoteName / sizeof s_NoteName[0]); return s_NoteName[nValue]; } -string CUIMenu::ToKeyboardCurve (int nValue) +std::string CUIMenu::ToMIDINote (int nValue, int nWidth) +{ + assert ((unsigned) nValue < sizeof s_MIDINoteName / sizeof *s_MIDINoteName); + + return s_MIDINoteName[nValue]; +} + +std::string CUIMenu::ToMIDINoteShift (int nValue, int nWidth) +{ + assert ((unsigned) nValue + 24 < sizeof s_MIDINoteShift / sizeof *s_MIDINoteShift); + + return s_MIDINoteShift[nValue + 24]; +} + +std::string CUIMenu::ToKeyboardCurve (int nValue, int nWidth) { static const char *Curve[] = {"-Lin", "-Exp", "+Exp", "+Lin"}; @@ -1182,7 +1864,7 @@ string CUIMenu::ToKeyboardCurve (int nValue) return Curve[nValue]; } -string CUIMenu::ToOscillatorMode (int nValue) +std::string CUIMenu::ToOscillatorMode (int nValue, int nWidth) { static const char *Mode[] = {"Ratio", "Fixed"}; @@ -1191,52 +1873,131 @@ string CUIMenu::ToOscillatorMode (int nValue) return Mode[nValue]; } -string CUIMenu::ToOscillatorDetune (int nValue) +std::string CUIMenu::ToOscillatorDetune (int nValue, int nWidth) { - string Result; + std::string Result; nValue -= 7; if (nValue > 0) { - Result = "+" + to_string (nValue); + Result = "+" + std::to_string (nValue); } else { - Result = to_string (nValue); + Result = std::to_string (nValue); } return Result; } -string CUIMenu::ToPortaMode (int nValue) +std::string CUIMenu::ToPortaMode (int nValue, int nWidth) { switch (nValue) { case 0: return "Fingered"; case 1: return "Full time"; - default: return to_string (nValue); + default: return std::to_string (nValue); } }; -string CUIMenu::ToPortaGlissando (int nValue) +std::string CUIMenu::ToPortaGlissando (int nValue, int nWidth) { switch (nValue) { case 0: return "Off"; case 1: return "On"; - default: return to_string (nValue); + default: return std::to_string (nValue); } }; -string CUIMenu::ToPolyMono (int nValue) +std::string CUIMenu::ToPolyMono (int nValue, int nWidth) { switch (nValue) { case 0: return "Poly"; case 1: return "Mono"; - default: return to_string (nValue); + default: return std::to_string (nValue); + } +} + +std::string CUIMenu::ToTGLinkName (int nValue, int nWidth) +{ + if (nValue == 0) return "-"; + return std::string{(char)(nValue + 'A' - 1)}; +} + +std::string CUIMenu::TodB (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dB"; +} + +std::string CUIMenu::TodBFS (int nValue, int nWidth) +{ + return std::to_string (nValue) + " dBFS"; +} + +std::string CUIMenu::ToMillisec (int nValue, int nWidth) +{ + return std::to_string (nValue) + " ms"; +} + +std::string CUIMenu::ToRatio (int nValue, int nWidth) +{ + if (nValue == CMiniDexed::CompressorRatioInf) + return "INF:1"; + + return std::to_string (nValue) + ":1"; +} + +std::string CUIMenu::ToHz (int nValue, int nWidth) +{ + uint16_t hz = MIDI_EQ_HZ[nValue]; + char buf[20] = {}; + + if (hz < 1000) + return std::to_string (hz) + " Hz"; + + std::snprintf (buf, sizeof(buf), "%.1f kHz", hz/1000.0); + return buf; +} + +void CUIMenu::GlobalShortcutHandler (TMenuEvent Event) +{ +#ifdef ARM_ALLOW_MULTI_CORE + if (m_pParentMenu == s_PlateReverbMenu || + m_pParentMenu == s_YKChorusMenu || + m_pParentMenu == s_DreamDelayMenu || + m_pParentMenu == s_FXEQMenu || + m_pParentMenu == s_CompressorMenu || + m_pParentMenu == s_EditCompressorMenu || + m_pParentMenu == s_EQMenu || + m_pCurrentMenu == s_TGMenu) + { + bool bSaveCurrentSelection = m_pCurrentMenu == s_TGMenu; + + unsigned nSavedSelection = m_nCurrentSelection; + + if (Event == MenuEventPressAndStepDown) + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepDown); + EventHandler (MenuEventSelect); + } + else + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepUp); + EventHandler (MenuEventSelect); + } + + if (bSaveCurrentSelection) + { + m_nCurrentSelection = nSavedSelection; + EventHandler (MenuEventUpdate); + } } +#endif } void CUIMenu::TGShortcutHandler (TMenuEvent Event) @@ -1250,22 +2011,41 @@ void CUIMenu::TGShortcutHandler (TMenuEvent Event) assert ( Event == MenuEventPressAndStepDown || Event == MenuEventPressAndStepUp); - if (Event == MenuEventPressAndStepDown) + + if (m_pParentMenu == s_EQMenu || m_pParentMenu == s_EditCompressorMenu) { - nTG--; + if (Event == MenuEventPressAndStepDown) + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepDown); + EventHandler (MenuEventSelect); + } + else + { + EventHandler (MenuEventBack); + EventHandler (MenuEventStepUp); + EventHandler (MenuEventSelect); + } } else { - nTG++; - } + if (Event == MenuEventPressAndStepDown) + { + nTG--; + } + else + { + nTG++; + } - if (nTG < m_nToneGenerators) - { - m_nMenuStackSelection[0] = nTG; - m_nMenuStackItem[1] = nTG; - m_nMenuStackParameter[1] = nTG; + if (nTG < m_nToneGenerators) + { + m_nMenuStackSelection[0] = nTG; + m_nMenuStackItem[1] = nTG; + m_nMenuStackParameter[1] = nTG; - EventHandler (MenuEventUpdate); + EventHandler (MenuEventUpdate); + } } } @@ -1390,7 +2170,7 @@ void CUIMenu::PgmUpDownHandler (TMenuEvent Event) // Skip empty voices. // Use same criteria in EditProgramNumber () too. - string voiceName = m_pMiniDexed->GetVoiceName (nTG); + std::string voiceName = m_pMiniDexed->GetVoiceName (nTG); if (voiceName == "EMPTY " || voiceName == " " || voiceName == "----------" @@ -1550,6 +2330,14 @@ void CUIMenu::TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pCont pThis->EventHandler (MenuEventBack); } +void CUIMenu::TimerHandlerUpdate (TKernelTimerHandle hTimer, void *pParam, void *pContext) +{ + CUIMenu *pThis = static_cast (pContext); + assert (pThis); + + pThis->EventHandler (MenuEventUpdate); +} + void CUIMenu::TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void *pContext) { CUIMenu *pThis = static_cast (pContext); @@ -1560,6 +2348,125 @@ void CUIMenu::TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void pThis->EventHandler (MenuEventUpdate); } +void CUIMenu::InputKeyDown (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + int nLastKeyDown = pUIMenu->m_pMiniDexed->GetLastKeyDown (); + CMiniDexed::TTGParameter Param = (CMiniDexed::TTGParameter) pUIMenu->m_nCurrentParameter; + unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2]; + pUIMenu->m_pMiniDexed->SetTGParameter(Param, nLastKeyDown, nTG); +} + +void CUIMenu::InputShiftKeyDown (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + int nLastKeyDown = pUIMenu->m_pMiniDexed->GetLastKeyDown () - MIDINoteC3; + CMiniDexed::TTGParameter Param = (CMiniDexed::TTGParameter) pUIMenu->m_nCurrentParameter; + unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2]; + if (nLastKeyDown >= -24 && nLastKeyDown <= 24) + pUIMenu->m_pMiniDexed->SetTGParameter(Param, nLastKeyDown, nTG); +} + +#ifdef ARM_ALLOW_MULTI_CORE + +void CUIMenu::SelectCurrentEffect (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + int nValue = pUIMenu->m_pMiniDexed->GetFXParameter (Param, nFX); + + if (!nValue) return; + + assert ((size_t)nValue < sizeof s_FXListMenu / sizeof *s_FXListMenu); + + pUIMenu->m_nCurrentSelection = nValue; +} + +void CUIMenu::StepDownEffect (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + int nValue = pUIMenu->m_nCurrentSelection; + int increment = rParam.Increment; + + while (true) + { + if (nValue - increment < rParam.Minimum) + { + increment = 0; + break; + } + + if (!FXSlotFilter(pUIMenu, Event, nValue - increment)) + break; + + increment += rParam.Increment; + } + + pUIMenu->m_nCurrentSelection -= increment; + + pUIMenu->m_pMiniDexed->SetFXParameter (Param, pUIMenu->m_nCurrentSelection, nFX); +} + +void CUIMenu::StepUpEffect (CUIMenu *pUIMenu, TMenuEvent Event) +{ + assert (pUIMenu); + + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + const FX::FXParameterType &rParam = FX::s_FXParameter[Param]; + int nValue = pUIMenu->m_nCurrentSelection; + int increment = rParam.Increment; + + while (true) + { + if (nValue + increment > rParam.Maximum) + { + increment = 0; + break; + } + + if (!FXSlotFilter(pUIMenu, Event, nValue + increment)) + break; + + increment += rParam.Increment; + } + + pUIMenu->m_nCurrentSelection += increment; + + pUIMenu->m_pMiniDexed->SetFXParameter (Param, pUIMenu->m_nCurrentSelection, nFX); +} + +bool CUIMenu::FXSlotFilter (CUIMenu *pUIMenu, TMenuEvent Event, int nValue) +{ + assert (pUIMenu); + FX::TFXParameter Param = (FX::TFXParameter) pUIMenu->m_nCurrentParameter; + + unsigned nFX = pUIMenu->m_nMenuStackParameter[2]; + + if (nValue == 0) return false; + + if (Param != FX::FXParameterSlot0 && nValue == pUIMenu->m_pMiniDexed->GetFXParameter(FX::FXParameterSlot0, nFX)) + return true; + + if (Param != FX::FXParameterSlot1 && nValue == pUIMenu->m_pMiniDexed->GetFXParameter(FX::FXParameterSlot1, nFX)) + return true; + + if (Param != FX::FXParameterSlot2 && nValue == pUIMenu->m_pMiniDexed->GetFXParameter(FX::FXParameterSlot2, nFX)) + return true; + + return false; +} + +#endif + void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { bool bPerformanceSelectToLoad = pUIMenu->m_pMiniDexed->GetPerformanceSelectToLoad(); @@ -1720,7 +2627,7 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { pUIMenu->m_nSelectedPerformanceID = 0; pUIMenu->m_bConfirmDeletePerformance=false; - pUIMenu->m_pUI->DisplayWrite ("", "Delete", pUIMenu->m_pMiniDexed->DeletePerformance(nValue) ? "Completed" : "Error", false, false); + pUIMenu->m_pMiniDexed->DisplayWrite ("", "Delete", pUIMenu->m_pMiniDexed->DeletePerformance(nValue) ? "Completed" : "Error", false, false); pUIMenu->m_bSplashShow=true; CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandlerNoBack, 0, pUIMenu); return; @@ -1753,13 +2660,13 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) nPSelected += " [L]"; } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), Value.c_str (), true, true); // (int) nValue > 0, (int) nValue < (int) pUIMenu->m_pMiniDexed->GetLastPerformance()); } else { - pUIMenu->m_pUI->DisplayWrite ("", "Delete?", pUIMenu->m_bConfirmDeletePerformance ? "Yes" : "No", false, false); + pUIMenu->m_pMiniDexed->DisplayWrite ("", "Delete?", pUIMenu->m_bConfirmDeletePerformance ? "Yes" : "No", false, false); } } @@ -1841,14 +2748,14 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) nPSelected += " [L]"; } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), Value.c_str (), true, true); } void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) { unsigned nTG=0; - string TG ("TG"); + std::string TG ("TG"); std::string MsgOk; std::string NoValidChars; @@ -1883,7 +2790,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) NoValidChars = {127}; MaxChars=10; MenuTitleL="Name"; - TG += to_string (nTG+1); + TG += std::to_string (nTG+1); MenuTitleR=TG; OkTitleL=""; OkTitleR=""; @@ -1952,7 +2859,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetNewPerformanceName(pUIMenu->m_InputText); bOK = pUIMenu->m_pMiniDexed->SavePerformanceNewFile (); MsgOk=bOK ? "Completed" : "Error"; - pUIMenu->m_pUI->DisplayWrite (OkTitleR.c_str(), OkTitleL.c_str(), MsgOk.c_str(), false, false); + pUIMenu->m_pMiniDexed->DisplayWrite (OkTitleR.c_str(), OkTitleL.c_str(), MsgOk.c_str(), false, false); CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandler, 0, pUIMenu); return; } @@ -1989,7 +2896,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) // \E[?25l Cursor invisible std::string escCursor="\E[?25h\E[2;"; // this is to locate cursor - escCursor += to_string(nPosition + 2); + escCursor += std::to_string(nPosition + 2); escCursor += "H"; @@ -2003,7 +2910,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) } Value = Value + " " + escCursor ; - pUIMenu->m_pUI->DisplayWrite (MenuTitleR.c_str(),MenuTitleL.c_str(), Value.c_str(), false, false); + pUIMenu->m_pMiniDexed->DisplayWrite (MenuTitleR.c_str(),MenuTitleL.c_str(), Value.c_str(), false, false); } @@ -2019,6 +2926,7 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) const TParameter &rParam = s_TGParameter[Param]; int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG); + int nTGLink = pUIMenu->m_pMiniDexed->GetTGParameter (CMiniDexed::TGParameterTGLink, nTG); switch (Event) { @@ -2052,49 +2960,17 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) return; } - string TG ("TG"); - TG += to_string (nTG+1); + std::string TG ("TG"); + TG += std::to_string (nTG+1); + if (nTGLink) TG += ToTGLinkName(nTGLink, 0); - string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); + std::string Value = GetTGValueString (Param, + pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG), + pUIMenu->m_pConfig->GetLCDColumns() - 2); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); } - -void CUIMenu::EditMasterVolume(CUIMenu *pUIMenu, TMenuEvent Event) -{ - TParameter rParam = {0, 127, 8, ToVolume}; - int nValue = pUIMenu->m_pMiniDexed->GetMasterVolume127(); - switch (Event) - { - case MenuEventUpdate: - case MenuEventUpdateParameter: - break; - case MenuEventStepDown: - nValue -= rParam.Increment; - if (nValue < rParam.Minimum) nValue = rParam.Minimum; - pUIMenu->m_pMiniDexed->setMasterVolume(nValue / 127.0f); - break; - case MenuEventStepUp: - nValue += rParam.Increment; - if (nValue > rParam.Maximum) nValue = rParam.Maximum; - pUIMenu->m_pMiniDexed->setMasterVolume(nValue / 127.0f); - break; - default: - return; - } - unsigned lcdCols = pUIMenu->m_pConfig->GetLCDColumns(); - unsigned barLen = (lcdCols > 2) ? lcdCols - 2 : 0; - std::string valueStr(barLen, '.'); - if (barLen > 0) { - size_t filled = (nValue * barLen + 63) / 127; - for (unsigned i = 0; i < barLen; ++i) { - if (i < filled) valueStr[i] = (char)0xFF; - } - } - // Do NOT add < or > here; let DisplayWrite handle it - pUIMenu->m_pUI->DisplayWrite("Master Volume", "", valueStr.c_str(), true, true); -} diff --git a/src/uimenu.h b/src/uimenu.h index 6c72f36c6..c305fceaa 100644 --- a/src/uimenu.h +++ b/src/uimenu.h @@ -33,7 +33,7 @@ class CUserInterface; class CUIMenu { private: - static const unsigned MaxMenuDepth = 5; + static const unsigned MaxMenuDepth = 6; public: enum TMenuEvent @@ -56,11 +56,46 @@ class CUIMenu MenuEventUnknown }; + typedef std::string TToString (int nValue, int nWidth); + + enum TCPageType + { + PageMain, + PageEffect, + PageTG, + PageVoice, + PageOP, + }; + + enum TCParameterType + { + ParameterNone, + ParameterGlobal, + ParameterTG, + ParameterVoice, + ParameterOP, + }; + + struct TCParameterInfo { + TCParameterType Type; + unsigned Parameter; + const char* Name; + const char* Short; + u8 ChG; + u8 TG; + u8 OP; + int Min; + int Max; + TToString *ToString; + }; + public: CUIMenu (CUserInterface *pUI, CMiniDexed *pMiniDexed, CConfig *pConfig); void EventHandler (TMenuEvent Event); + const void GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n); + private: typedef void TMenuHandler (CUIMenu *pUIMenu, TMenuEvent Event); @@ -70,10 +105,14 @@ class CUIMenu TMenuHandler *Handler; const TMenuItem *MenuItem; unsigned Parameter; + const char *Short; + TMenuHandler* OnSelect; + TMenuHandler* StepDown; + TMenuHandler* StepUp; + unsigned Parameter2; + bool ShowDirect; }; - typedef std::string TToString (int nValue); - struct TParameter { int Minimum; @@ -88,6 +127,8 @@ class CUIMenu static void EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); static void EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event); static void EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event); + static void EditFXParameter2 (CUIMenu *pUIMenu, TMenuEvent Event); + static void EditFXParameterG (CUIMenu *pUIMenu, TMenuEvent Event); static void EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event); @@ -96,29 +137,43 @@ class CUIMenu static void PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event); static void SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event); static void EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event); - static void EditMasterVolume (CUIMenu *pUIMenu, TMenuEvent Event); - - static std::string GetGlobalValueString (unsigned nParameter, int nValue); - static std::string GetTGValueString (unsigned nTGParameter, int nValue); - static std::string GetVoiceValueString (unsigned nVoiceParameter, int nValue); - static std::string GetOPValueString (unsigned nOPParameter, int nValue); - - static std::string ToVolume (int nValue); - static std::string ToPan (int nValue); - static std::string ToMIDIChannel (int nValue); - - static std::string ToAlgorithm (int nValue); - static std::string ToOnOff (int nValue); - static std::string ToLFOWaveform (int nValue); - static std::string ToTransposeNote (int nValue); - static std::string ToBreakpointNote (int nValue); - static std::string ToKeyboardCurve (int nValue); - static std::string ToOscillatorMode (int nValue); - static std::string ToOscillatorDetune (int nValue); - static std::string ToPortaMode (int nValue); - static std::string ToPortaGlissando (int nValue); - static std::string ToPolyMono (int nValue); + static void ShowCPUTemp (CUIMenu *pUIMenu, TMenuEvent Event); + static void ShowCPUSpeed (CUIMenu *pUIMenu, TMenuEvent Event); + static void ShowIPAddr (CUIMenu *pUIMenu, TMenuEvent Event); + static void ShowVersion (CUIMenu *pUIMenu, TMenuEvent Event); + + static std::string GetGlobalValueString (unsigned nParameter, int nValue, int nWidth); + static std::string GetTGValueString (unsigned nTGParameter, int nValue, int nWidth); + static std::string GetFXValueString (unsigned nFXParameter, int nValue, int nWidth); + static std::string GetVoiceValueString (unsigned nVoiceParameter, int nValue, int nWidth); + static std::string GetOPValueString (unsigned nOPParameter, int nValue, int nWidth); + + static std::string ToVolume (int nValue, int nWidth); + static std::string ToPan (int nValue, int nWidth); + static std::string ToMIDIChannel (int nValue, int nWidth); + + static std::string ToAlgorithm (int nValue, int nWidth); + static std::string ToOnOff (int nValue, int nWidth); + static std::string ToLFOWaveform (int nValue, int nWidth); + static std::string ToTransposeNote (int nValue, int nWidth); + static std::string ToBreakpointNote (int nValue, int nWidth); + static std::string ToMIDINote (int nValue, int nWidth); + static std::string ToMIDINoteShift (int nValue, int nWidth); + static std::string ToKeyboardCurve (int nValue, int nWidth); + static std::string ToOscillatorMode (int nValue, int nWidth); + static std::string ToOscillatorDetune (int nValue, int nWidth); + static std::string ToPortaMode (int nValue, int nWidth); + static std::string ToPortaGlissando (int nValue, int nWidth); + static std::string ToPolyMono (int nValue, int nWidth); + static std::string ToTGLinkName (int nValue, int nWidth); + static std::string TodB (int nValue, int nWidth); + static std::string TodBFS (int nValue, int nWidth); + static std::string ToMillisec (int nValue, int nWidth); + static std::string ToRatio (int nValue, int nWidth); + static std::string ToHz (int nValue, int nWidth); + + void GlobalShortcutHandler (TMenuEvent Event); void TGShortcutHandler (TMenuEvent Event); void OPShortcutHandler (TMenuEvent Event); @@ -127,10 +182,20 @@ class CUIMenu void TGUpDownHandler (TMenuEvent Event); static void TimerHandler (TKernelTimerHandle hTimer, void *pParam, void *pContext); + static void TimerHandlerUpdate (TKernelTimerHandle hTimer, void *pParam, void *pContext); static void InputTxt (CUIMenu *pUIMenu, TMenuEvent Event); static void TimerHandlerNoBack (TKernelTimerHandle hTimer, void *pParam, void *pContext); + + static void InputKeyDown (CUIMenu *pUIMenu, TMenuEvent Event); + static void InputShiftKeyDown (CUIMenu *pUIMenu, TMenuEvent Event); + + static void SelectCurrentEffect (CUIMenu *pUIMenu, TMenuEvent Event); + static void StepDownEffect (CUIMenu *pUIMenu, TMenuEvent Event); + static void StepUpEffect (CUIMenu *pUIMenu, TMenuEvent Event); + static bool FXSlotFilter (CUIMenu *pUIMenu, TMenuEvent Event, int nValue); + const void GetParameterInfo (TCParameterInfo *pParam); private: CUserInterface *m_pUI; CMiniDexed *m_pMiniDexed; @@ -154,24 +219,47 @@ class CUIMenu static const TMenuItem s_MenuRoot[]; static const TMenuItem s_MainMenu[]; static const TMenuItem s_TGMenu[]; + static const TMenuItem s_SendFXMenu[]; + static const TMenuItem s_MasterFXMenu[]; + static const TMenuItem s_FXListMenu[]; + static const TMenuItem s_MixerMenu[]; static const TMenuItem s_EffectsMenu[]; - static const TMenuItem s_ReverbMenu[]; + static const TMenuItem s_EQMenu[]; + static const TMenuItem s_YKChorusMenu[]; + static const TMenuItem s_DreamDelayMenu[]; + static const TMenuItem s_PlateReverbMenu[]; + static const TMenuItem s_CloudSeed2Menu[]; + static const TMenuItem s_CloudSeed2InputMenu[]; + static const TMenuItem s_CloudSeed2MultitapMenu[]; + static const TMenuItem s_CloudSeed2EarlyDiffusionMenu[]; + static const TMenuItem s_CloudSeed2LateDiffusionMenu[]; + static const TMenuItem s_CloudSeed2LateLineMenu[]; + static const TMenuItem s_CloudSeed2LowShelfMenu[]; + static const TMenuItem s_CloudSeed2HighShelfMenu[]; + static const TMenuItem s_CloudSeed2LowPassMenu[]; + static const TMenuItem s_CompressorMenu[]; + static const TMenuItem s_FXEQMenu[]; + static const TMenuItem s_EditCompressorMenu[]; static const TMenuItem s_EditVoiceMenu[]; static const TMenuItem s_OperatorMenu[]; static const TMenuItem s_SaveMenu[]; static const TMenuItem s_EditPitchBendMenu[]; static const TMenuItem s_EditPortamentoMenu[]; + static const TMenuItem s_EditNoteLimitMenu[]; static const TMenuItem s_PerformanceMenu[]; + static const TMenuItem s_StatusMenu[]; static const TMenuItem s_ModulationMenu[]; static const TMenuItem s_ModulationMenuParameters[]; - static const TParameter s_GlobalParameter[]; - static const TParameter s_TGParameter[]; + static TParameter s_GlobalParameter[]; + static TParameter s_TGParameter[]; static const TParameter s_VoiceParameter[]; static const TParameter s_OPParameter[]; static const char s_NoteName[100][5]; + static const char s_MIDINoteName[128][9]; + static const char s_MIDINoteShift[49][8]; std::string m_InputText="1234567890ABCD"; unsigned m_InputTextPosition=0; diff --git a/src/usbminidexedmidigadget.h b/src/usbminidexedmidigadget.h index 851354955..977d53622 100644 --- a/src/usbminidexedmidigadget.h +++ b/src/usbminidexedmidigadget.h @@ -24,7 +24,7 @@ #if RASPPI==5 #include -#include +#include #warning No support for USB Gadget Mode on RPI 5 yet class CUSBMiniDexedMIDIGadget diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 43a94ff46..492e4eb1e 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -22,8 +22,8 @@ #include #include #include -#include -#include +#include +#include LOGMODULE ("ui"); @@ -199,6 +199,27 @@ bool CUserInterface::Initialize (void) return true; } +void CUserInterface::LoadDefaultScreen () +{ + // performance load + if (m_pConfig->GetDefaultScreen() == 1) + { + m_Menu.EventHandler (CUIMenu::MenuEventStepDown); + m_Menu.EventHandler (CUIMenu::MenuEventSelect); + m_Menu.EventHandler (CUIMenu::MenuEventSelect); + } +} + +void CUserInterface::MIDIEventHandler (CUIMenu::TMenuEvent Event) +{ + m_Menu.EventHandler (Event); +} + +const void CUserInterface::GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n) +{ + m_Menu.GetParameterInfos (pParamInfo, n); +} + void CUserInterface::Process (void) { if (m_pLCDBuffered) @@ -214,6 +235,7 @@ void CUserInterface::Process (void) void CUserInterface::ParameterChanged (void) { m_Menu.EventHandler (CUIMenu::MenuEventUpdateParameter); + m_pMiniDexed->UpdateDAWState (); } void CUserInterface::DisplayChanged (void) @@ -228,52 +250,64 @@ void CUserInterface::DisplayWrite (const char *pMenu, const char *pParam, const assert (pParam); assert (pValue); - CString Msg ("\x1B[H\E[?25l"); // cursor home and off + size_t nLineMaxLen = m_pConfig->GetLCDColumns (); - // first line - Msg.Append (pParam); + const char* pHdr = "\x1B[H\E[?25l"; // cursor home and off + size_t nHdrLen = strlen(pHdr); - size_t nLen = strlen (pParam) + strlen (pMenu); - if (nLen < m_pConfig->GetLCDColumns ()) - { - for (unsigned i = m_pConfig->GetLCDColumns ()-nLen; i > 0; i--) - { - Msg.Append (" "); - } - } + const char* pClear = "\x1B[K"; // clear end of line + size_t nClearLen = strlen(pClear); - Msg.Append (pMenu); + size_t nParamLen = std::min (nLineMaxLen, strlen (pParam)); + size_t nMenuLen = strlen (pMenu); + size_t nFill1Len = nLineMaxLen > nParamLen + nMenuLen ? + nLineMaxLen - nParamLen - nMenuLen : 1; - // second line - CString Value (" "); - if (bArrowDown) - { - Value = "<"; // arrow left character - } + nFill1Len = std:: min (nLineMaxLen - nParamLen, nFill1Len); + nMenuLen = std::min (nLineMaxLen - nParamLen - nFill1Len, nMenuLen); - Value.Append (pValue); + size_t nLine1Len = nParamLen + nFill1Len + nMenuLen; - if (bArrowUp) - { - if (Value.GetLength () < m_pConfig->GetLCDColumns ()-1) - { - for (unsigned i = m_pConfig->GetLCDColumns ()-Value.GetLength ()-1; i > 0; i--) - { - Value.Append (" "); - } - } + size_t nArrowsLen = 2; + size_t nValueLen = std::min (nLineMaxLen - nArrowsLen, strlen (pValue)); + size_t nFill2Len = bArrowUp ? nLineMaxLen - nArrowsLen - nValueLen : 0; + size_t nLine2Len = nValueLen + nFill2Len + nArrowsLen; - Value.Append (">"); // arrow right character - } + if (nLine2Len >= nLineMaxLen) + nClearLen = 0; - Msg.Append (Value); + size_t nOffset = 0; - if (Value.GetLength () < m_pConfig->GetLCDColumns ()) - { - Msg.Append ("\x1B[K"); // clear end of line - } + char pLines[nHdrLen + nLine1Len + nLine2Len + nClearLen + 1]; + + memcpy (pLines, pHdr, nHdrLen); + nOffset += nHdrLen; + + memcpy (pLines + nOffset, pParam, nParamLen); + nOffset += nParamLen; + + memset (pLines + nOffset, ' ', nFill1Len); + nOffset += nFill1Len; + + memcpy (pLines + nOffset, pMenu, nMenuLen); + nOffset += nMenuLen; + + pLines[nOffset++] = bArrowDown ? '<' : ' '; + + memcpy (pLines + nOffset, pValue, nValueLen); + nOffset += nValueLen; + + memset (pLines + nOffset, ' ', nFill2Len); + nOffset += nFill2Len; + + pLines[nOffset++] = bArrowUp ? '>' : ' '; + + memcpy (pLines + nOffset, pClear, nClearLen); + nOffset += nClearLen; + + pLines[nOffset++] = 0; - LCDWrite (Msg); + LCDWrite ((const char *)pLines); } void CUserInterface::LCDWrite (const char *pString) diff --git a/src/userinterface.h b/src/userinterface.h index 6290d865b..aa5ef9fa1 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -42,6 +42,8 @@ class CUserInterface bool Initialize (void); + void LoadDefaultScreen (); + void Process (void); void ParameterChanged (void); @@ -58,6 +60,10 @@ class CUserInterface // To be called from the MIDI device on reception of a MIDI CC message void UIMIDICmdHandler (unsigned nMidiCh, unsigned nMidiType, unsigned nMidiData1, unsigned nMidiData2); + void MIDIEventHandler (CUIMenu::TMenuEvent Event); + + const void GetParameterInfos (CUIMenu::TCParameterInfo *pParamInfo, size_t n); + private: void LCDWrite (const char *pString); // Print to optional HD44780 display diff --git a/src/ykchorus/Chorus.h b/src/ykchorus/Chorus.h new file mode 100644 index 000000000..603e6bb06 --- /dev/null +++ b/src/ykchorus/Chorus.h @@ -0,0 +1,143 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__Chorus_h) +#define __Chorus_h + +#include "OnePoleLP.h" +#include "math.h" + +class Chorus { +public: + float *delayLineStart; + float *delayLineEnd; + float *writePtr; + + int delayLineLength; + float rate; + float delayLineOutput; + + float sampleRate; + float delayTime; + + // Runtime variables + float offset, diff, frac, *ptr, *ptr2; + + int readPos; + + OnePoleLP *lp; + float z1; + float mult, sign; + + // lfo + float lfoPhase, lfoStepSize, lfoSign; + + Chorus(float sampleRate, float phase, float rate, float delayTime) { + this->rate = rate; + this->sampleRate = sampleRate; + this->delayTime = delayTime; + z1 = 0.0f; + sign = 0; + lfoPhase = phase * 2.0f - 1.0f; + lfoStepSize = (4.0f * rate / sampleRate); + lfoSign = 1.0f; + + // Compute required buffer size for desired delay and allocate it + // Add extra point to aid in interpolation later + delayLineLength = ((int)floorf(delayTime * sampleRate * 0.001f) * 2); + delayLineStart = new float[delayLineLength]; + + // Set up pointers for delay line + delayLineEnd = delayLineStart + delayLineLength; + writePtr = delayLineStart; + + // Zero out the buffer (silence) + do { + *writePtr = 0.0f; + } + while (++writePtr < delayLineEnd); + + // Set read pointer to end of delayline. Setting it to the end + // ensures the interpolation below works correctly to produce + // the first non-zero sample. + writePtr = delayLineStart + delayLineLength -1; + delayLineOutput = 0.0f; + lp = new OnePoleLP(); + } + + ~Chorus() { + delete[] delayLineStart; + delete lp; + } + + void setLfoRate(float rate) { + this->rate = rate; + lfoStepSize = (4.0f * rate / sampleRate); + } + + float process(float *sample) { + // Get delay time + offset = (nextLFO() * 0.3f + 0.4f) * delayTime * sampleRate * 0.001f; + + // Compute the largest read pointer based on the offset. If ptr + // is before the first delayline location, wrap around end point + ptr = writePtr - (int)floorf(offset); + if (ptr < delayLineStart) + ptr += delayLineLength; + + ptr2 = ptr - 1; + if (ptr2 < delayLineStart) + ptr2 += delayLineLength; + + frac = offset - (int)floorf(offset); + delayLineOutput = *ptr2 + *ptr * (1 - frac) - (1 - frac) * z1; + z1 = delayLineOutput; + + // Low pass + lp->tick(&delayLineOutput, 0.95f); + + // Write the input sample and any feedback to delayline + *writePtr = *sample; + + // Increment buffer index and wrap if necesary + if (++writePtr >= delayLineEnd) { + writePtr = delayLineStart; + } + return delayLineOutput; + } + + inline float nextLFO() { + if (lfoPhase >= 1.0f) + { + lfoSign = -1.0f; + } + else if (lfoPhase <= -1.0f) + { + lfoSign = +1.0f; + } + lfoPhase += lfoStepSize * lfoSign; + return lfoPhase; + } +}; + +#endif \ No newline at end of file diff --git a/src/ykchorus/ChorusEngine.h b/src/ykchorus/ChorusEngine.h new file mode 100644 index 000000000..cb30c66e0 --- /dev/null +++ b/src/ykchorus/ChorusEngine.h @@ -0,0 +1,114 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__ChorusEngine_h) +#define __ChorusEngine_h + +#include "Chorus.h" +#include "DCBlock.h" + + +class ChorusEngine { +public: + Chorus *chorus1L; + Chorus *chorus1R; + Chorus *chorus2L; + Chorus *chorus2R; + + DCBlock *dcBlock1L; + DCBlock *dcBlock1R; + DCBlock *dcBlock2L; + DCBlock *dcBlock2R; + + bool isChorus1Enabled; + bool isChorus2Enabled; + + ChorusEngine(float sampleRate) { + dcBlock1L = new DCBlock(); + dcBlock1R = new DCBlock(); + dcBlock2L = new DCBlock(); + dcBlock2R = new DCBlock(); + + setUpChorus(sampleRate); + } + + ~ChorusEngine() { + delete chorus1L; + delete chorus1R; + delete chorus2L; + delete chorus2R; + delete dcBlock1L; + delete dcBlock1R; + delete dcBlock2L; + delete dcBlock2R; + } + + void setSampleRate(float sampleRate) { + setUpChorus(sampleRate); + } + + void setEnablesChorus(bool isChorus1Enabled, bool isChorus2Enabled) { + this->isChorus1Enabled = isChorus1Enabled; + this->isChorus2Enabled = isChorus2Enabled; + } + + void setChorus1LfoRate(float rate) { + chorus1L->setLfoRate(rate); + chorus1R->setLfoRate(rate); + } + + void setChorus2LfoRate(float rate) { + chorus2L->setLfoRate(rate); + chorus2R->setLfoRate(rate); + } + + void setUpChorus(float sampleRate) { + chorus1L = new Chorus(sampleRate, 1.0f, 0.5f, 7.0f); + chorus1R = new Chorus(sampleRate, 0.0f, 0.5f, 7.0f); + chorus2L = new Chorus(sampleRate, 0.0f, 0.83f, 7.0f); + chorus2R = new Chorus(sampleRate, 1.0f, 0.83f, 7.0f); + } + + inline void process(float dry, float wet, float *sampleL, float *sampleR) { + float resultR = 0.0f; + float resultL = 0.0f; + if (isChorus1Enabled) + { + resultL += chorus1L->process(sampleL); + resultR += chorus1R->process(sampleR); + dcBlock1L->tick(&resultL, 0.01f); + dcBlock1R->tick(&resultR, 0.01f); + } + if (isChorus2Enabled) + { + resultL += chorus2L->process(sampleL); + resultR += chorus2R->process(sampleR); + dcBlock2L->tick(&resultL, 0.01f); + dcBlock2R->tick(&resultR, 0.01f); + } + *sampleL = dry * *sampleL + wet * resultL * 1.4f; + *sampleR = dry * *sampleR + wet * resultR * 1.4f; + } +}; + +#endif \ No newline at end of file diff --git a/src/ykchorus/DCBlock.h b/src/ykchorus/DCBlock.h new file mode 100644 index 000000000..40dc1e427 --- /dev/null +++ b/src/ykchorus/DCBlock.h @@ -0,0 +1,45 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__DCBlock_h) +#define __DCBlock_h + +class DCBlock { +public: + float inputs, outputs, lastOutput; + + DCBlock() { + lastOutput = inputs = outputs = 0.0f; + } + + ~DCBlock() {} + + inline void tick(float *sample, float cutoff) { + outputs = *sample - inputs + (0.999f - cutoff * 0.4f) * outputs; + inputs = *sample; + lastOutput = outputs; + *sample = lastOutput; + } +}; + +#endif \ No newline at end of file diff --git a/src/ykchorus/OnePoleLP.h b/src/ykchorus/OnePoleLP.h new file mode 100644 index 000000000..955ed53cd --- /dev/null +++ b/src/ykchorus/OnePoleLP.h @@ -0,0 +1,44 @@ +/* + ============================================================================== + This file is part of Tal-NoiseMaker by Patrick Kunz. + + Copyright(c) 2005-2010 Patrick Kunz, TAL + Togu Audio Line, Inc. + http://kunz.corrupt.ch + + This file may be licensed under the terms of of the + GNU General Public License Version 2 (the ``GPL''). + + Software distributed under the License is distributed + on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either + express or implied. See the GPL for the specific language + governing rights and limitations. + + You should have received a copy of the GPL along with this + program. If not, go to http://www.gnu.org/licenses/gpl.html + or write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ============================================================================== + */ + +#if !defined(__OnePoleLP_h) +#define __OnePoleLP_h + +class OnePoleLP { +public: + float inputs, outputs, lastOutput; + + OnePoleLP() { + lastOutput = inputs = outputs = 0.0f; + } + + ~OnePoleLP() {} + + void tick(float *sample, float cutoff) { + float p = (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f); + outputs = (1.0f - p) * (*sample) + p * outputs; + *sample = outputs; + } +}; + +#endif \ No newline at end of file diff --git a/submod.sh b/submod.sh index 28d467bba..4b584c06a 100755 --- a/submod.sh +++ b/submod.sh @@ -5,19 +5,19 @@ set -ex git submodule update --init --recursive -f # Use fixed master branch of circle-stdlib then re-update -cd circle-stdlib/ -git checkout -f --recurse-submodules 1111eee # Matches Circle Step49 -cd - +#cd circle-stdlib/ +#git checkout -f --recurse-submodules 1111eee # Matches Circle Step49 +#cd - # Optional update submodules explicitly -cd circle-stdlib/libs/circle -git checkout -f --recurse-submodules f18c60fa38042ea7132533e658abfafd5bd63435 -cd - +#cd circle-stdlib/libs/circle +#git checkout -f --recurse-submodules f18c60fa38042ea7132533e658abfafd5bd63435 +#cd - #cd circle-stdlib/libs/circle-newlib #git checkout develop #cd - # Use fixed master branch of Synth_Dexed -cd Synth_Dexed/ -git checkout -f 3c683fc801 -cd - +#cd Synth_Dexed/ +#git checkout -f a02b5c0bf2da132f49a923f9c69796220a8ea93f +#cd -