diff --git a/.gitmodules b/.gitmodules
index 064ffe4..96cb8bb 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,3 +7,6 @@
[submodule "CMSIS_5"]
path = CMSIS_5
url = https://github.com/ARM-software/CMSIS_5
+[submodule "u8g2"]
+ path = u8g2
+ url = https://github.com/olikraus/u8g2.git
diff --git a/.vscode/configurationCache.log b/.vscode/configurationCache.log
new file mode 100644
index 0000000..bab9054
--- /dev/null
+++ b/.vscode/configurationCache.log
@@ -0,0 +1 @@
+{"buildTargets":[],"launchTargets":[],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":[],"compilerArgs":[]},"fileIndex":[]}}
\ No newline at end of file
diff --git a/.vscode/dryrun.log b/.vscode/dryrun.log
new file mode 100644
index 0000000..ed74b6a
--- /dev/null
+++ b/.vscode/dryrun.log
@@ -0,0 +1,4 @@
+make.exe --dry-run --keep-going --print-directory
+'make.exe' is not recognized as an internal or external command,
+operable program or batch file.
+
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..65e1ec0
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "makefile.extensionOutputFolder": "./.vscode"
+}
\ No newline at end of file
diff --git a/.vscode/targets.log b/.vscode/targets.log
new file mode 100644
index 0000000..04f2128
--- /dev/null
+++ b/.vscode/targets.log
@@ -0,0 +1,4 @@
+make.exe all --print-data-base --no-builtin-variables --no-builtin-rules --question
+'make.exe' is not recognized as an internal or external command,
+operable program or batch file.
+
diff --git a/README.md b/README.md
index 8070e57..ecd020b 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,10 @@
-# MiniDexed ![](https://github.com/probonopd/MiniDexed/actions/workflows/build.yml/badge.svg)
+# MaxiDexed ![](https://github.com/probonopd/MiniDexed/actions/workflows/build.yml/badge.svg)
+
+This project aims at increasing the marvelous job done with MiniDexed focusing on the user interface as I believe that FM synthesis is difficult enough to deserve a simple but more confortable user interface to replace the 2x16 chars displays and the one button with click, double clicks and triple clicks! As you guessed it, I want to make it autonomous from computer assistance.
+
+I added at the tip of the feature list the few features I would like to contribute in this fork.
+
+For the moment this fork will concentrate on Raspberry PI 4B and potentialy above. I do not intent to test the code on any other lower versions.
![minidexed](https://user-images.githubusercontent.com/2480569/161813414-bb156a1c-efec-44c0-802a-8926412a08e0.jpg)
@@ -6,6 +12,32 @@ MiniDexed is a FM synthesizer closely modeled on the famous DX7 by a well-known
## Features
+### Maxi Dexed features backlog
+- [ ] DEV01 - Change build structure so that object and other bin files go away from the sources directories
+- [x] PRESET01 - Preset browsing: changing bak automaticallw when reaching the left or right preset boundary so that:
+```
+ - Bank 1 Preset 1 + 1 -> Bank 1 Preset 2
+ - Bank 1 Preset 1 - 1 -> Bank 1 Preset 1
+ - Bank n Preset 32 + 1 -> Bank n+1 Preset 1
+ - Bank n Preset 1 - 1 -> Bank n-1 Preset 32
+```
+- [x] PRESET02 - Support more than 127 banks adding the support MIDI CC0 [Bank Select (MSB)] et MIDI CC32 [Bank Select (LSB)] to allow a maximum of 2^14 = 16384 so that:
+```
+ - Bank ID bin: nn nnnn nnnn nnnn
+ - MIDI CC 0: nn nnnn nxxx xxxx
+ - MIDI CC 32: xx xxxx xnnn nnnn
+```
+- [x] PRESET03 - Add bank sysex material to complement the current one
+- [ ] PRESET04 - Add performance support and edit to leverage the 8 Tone Generators
+- [ ] SYNTH01 - Add Delay FX
+- [ ] SYNTH02 - Add Chorus FX
+- [ ] SYNTH03 - Add Flanger FX
+- [ ] SYNTH04 - Add Distortion FX
+- [-] HW01 - Create a 3D printable enclosure for the synth that uses the Raspaudio option
+- [ ] HW02 - Add support for I2C screen interface (4pins)
+- [ ] HW03 - Build PCB to ease the inclusion of all encoders, the screen and the audio sound card and include passive heat dissipation (OOTS Raspberry PI heatsink such as [GeeekPi Raspberry Pi 4](https://www.amazon.fr/gp/product/B07WQT1RRZ/ref=sw_img_1?smid=A187Y4UVM6ZA0X&th=1))
+- [ ] HW04 - Design a metal enclosure with real size inputs and outputs
+### MiniDexed feature backlog
- [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
diff --git a/analysis/MenuStructure.xlsx b/analysis/MenuStructure.xlsx
new file mode 100644
index 0000000..800c1f0
Binary files /dev/null and b/analysis/MenuStructure.xlsx differ
diff --git a/analysis/algorithms.jpg b/analysis/algorithms.jpg
new file mode 100644
index 0000000..320a19b
Binary files /dev/null and b/analysis/algorithms.jpg differ
diff --git a/getsysex.sh b/getsysex.sh
index fa73153..b7b5085 100755
--- a/getsysex.sh
+++ b/getsysex.sh
@@ -7,10 +7,10 @@ mkdir -p sysex/voice/
DIR="https://yamahablackboxes.com/patches/dx7/factory"
-# wget -c "${DIR}"/rom1a.syx -O sysex/voice/000000_rom1a.syx
-# wget -c "${DIR}"/rom1b.syx -O sysex/voice/000001_rom1b.syx
-# wget -c "${DIR}"/rom2a.syx -O sysex/voice/000002_rom2a.syx
-# wget -c "${DIR}"/rom2b.syx -O sysex/voice/000003_rom2b.syx
+wget -c "${DIR}"/rom1a.syx -O sysex/voice/000000_rom1a.syx
+wget -c "${DIR}"/rom1b.syx -O sysex/voice/000001_rom1b.syx
+wget -c "${DIR}"/rom2a.syx -O sysex/voice/000002_rom2a.syx
+wget -c "${DIR}"/rom2b.syx -O sysex/voice/000003_rom2b.syx
wget -c "${DIR}"/rom3a.syx -O sysex/voice/000000_rom3a.syx
wget -c "${DIR}"/rom3b.syx -O sysex/voice/000001_rom3b.syx
wget -c "${DIR}"/rom4a.syx -O sysex/voice/000002_rom4a.syx
@@ -41,3 +41,510 @@ wget -c "${DIR}"/vrc111a.syx -O sysex/voice/000023_vrc111a.syx
wget -c "${DIR}"/vrc111b.syx -O sysex/voice/000024_vrc111b.syx
wget -c "${DIR}"/vrc112a.syx -O sysex/voice/000025_vrc112a.syx
wget -c "${DIR}"/vrc112b.syx -O sysex/voice/000026_vrc112b.syx
+
+DIR="http://dxsysex.com/SYSEX_DX7/Misc"
+
+wget -c "${DIR}"/actualbk.syx -O sysex/voice/000027_actualbk.syx
+wget -c "${DIR}"/aegix.syx -O sysex/voice/000028_aegix.syx
+wget -c "${DIR}"/analog1.syx -O sysex/voice/000029_analog1.syx
+wget -c "${DIR}"/analog3.syx -O sysex/voice/000030_analog3.syx
+wget -c "${DIR}"/analog4.syx -O sysex/voice/000031_analog4.syx
+wget -c "${DIR}"/analog_1.syx -O sysex/voice/000032_analog_1.syx
+wget -c "${DIR}"/analog_2.syx -O sysex/voice/000033_analog_2.syx
+wget -c "${DIR}"/analog_3.syx -O sysex/voice/000034_analog_3.syx
+wget -c "${DIR}"/angelo.syx -O sysex/voice/000035_angelo.syx
+wget -c "${DIR}"/atsu_4.syx -O sysex/voice/000036_atsu_4.syx
+wget -c "${DIR}"/atsu_5.syx -O sysex/voice/000037_atsu_5.syx
+wget -c "${DIR}"/b1.syx -O sysex/voice/000038_b1.syx
+wget -c "${DIR}"/b2.syx -O sysex/voice/000039_b2.syx
+wget -c "${DIR}"/b3.syx -O sysex/voice/000040_b3.syx
+wget -c "${DIR}"/b4.syx -O sysex/voice/000041_b4.syx
+wget -c "${DIR}"/bank0000.syx -O sysex/voice/000042_bank0000.syx
+wget -c "${DIR}"/bank0006.syx -O sysex/voice/000043_bank0006.syx
+wget -c "${DIR}"/bank0008.syx -O sysex/voice/000044_bank0008.syx
+wget -c "${DIR}"/bank0009.syx -O sysex/voice/000045_bank0009.syx
+wget -c "${DIR}"/bank0023.syx -O sysex/voice/000046_bank0023.syx
+wget -c "${DIR}"/bank0024.syx -O sysex/voice/000047_bank0024.syx
+wget -c "${DIR}"/bank0042.syx -O sysex/voice/000048_bank0042.syx
+wget -c "${DIR}"/bank0043.syx -O sysex/voice/000049_bank0043.syx
+wget -c "${DIR}"/bank0044.syx -O sysex/voice/000050_bank0044.syx
+wget -c "${DIR}"/bank0045.syx -O sysex/voice/000051_bank0045.syx
+wget -c "${DIR}"/bank0046.syx -O sysex/voice/000052_bank0046.syx
+wget -c "${DIR}"/bank0047.syx -O sysex/voice/000053_bank0047.syx
+wget -c "${DIR}"/bank0048.syx -O sysex/voice/000054_bank0048.syx
+wget -c "${DIR}"/bank0049.syx -O sysex/voice/000055_bank0049.syx
+wget -c "${DIR}"/bank0050.syx -O sysex/voice/000056_bank0050.syx
+wget -c "${DIR}"/bank0054.syx -O sysex/voice/000057_bank0054.syx
+wget -c "${DIR}"/bank0056.syx -O sysex/voice/000058_bank0056.syx
+wget -c "${DIR}"/bank01.syx -O sysex/voice/000059_bank01.syx
+wget -c "${DIR}"/bank05.syx -O sysex/voice/000060_bank05.syx
+wget -c "${DIR}"/bank08.syx -O sysex/voice/000061_bank08.syx
+wget -c "${DIR}"/bank1.syx -O sysex/voice/000062_bank1.syx
+wget -c "${DIR}"/bank11.syx -O sysex/voice/000063_bank11.syx
+wget -c "${DIR}"/bank14.syx -O sysex/voice/000064_bank14.syx
+wget -c "${DIR}"/bank18.syx -O sysex/voice/000065_bank18.syx
+wget -c "${DIR}"/bank2.syx -O sysex/voice/000066_bank2.syx
+wget -c "${DIR}"/bank3.syx -O sysex/voice/000067_bank3.syx
+wget -c "${DIR}"/bass3.syx -O sysex/voice/000068_bass3.syx
+wget -c "${DIR}"/bass_01.syx -O sysex/voice/000069_bass_01.syx
+wget -c "${DIR}"/bass_02.syx -O sysex/voice/000070_bass_02.syx
+wget -c "${DIR}"/bass_03.syx -O sysex/voice/000071_bass_03.syx
+wget -c "${DIR}"/bass_04.syx -O sysex/voice/000072_bass_04.syx
+wget -c "${DIR}"/bass_05.syx -O sysex/voice/000073_bass_05.syx
+wget -c "${DIR}"/bass_06.syx -O sysex/voice/000074_bass_06.syx
+wget -c "${DIR}"/bass_07.syx -O sysex/voice/000075_bass_07.syx
+wget -c "${DIR}"/bass_08.syx -O sysex/voice/000076_bass_08.syx
+wget -c "${DIR}"/bass_09.syx -O sysex/voice/000077_bass_09.syx
+wget -c "${DIR}"/bass_10.syx -O sysex/voice/000078_bass_10.syx
+wget -c "${DIR}"/bass_11.syx -O sysex/voice/000079_bass_11.syx
+wget -c "${DIR}"/bass_12.syx -O sysex/voice/000080_bass_12.syx
+wget -c "${DIR}"/bass_13.syx -O sysex/voice/000081_bass_13.syx
+wget -c "${DIR}"/bass_14.syx -O sysex/voice/000082_bass_14.syx
+wget -c "${DIR}"/bass_15.syx -O sysex/voice/000083_bass_15.syx
+wget -c "${DIR}"/bassea.syx -O sysex/voice/000084_bassea.syx
+wget -c "${DIR}"/bassics.syx -O sysex/voice/000085_bassics.syx
+wget -c "${DIR}"/bbank1.syx -O sysex/voice/000086_bbank1.syx
+wget -c "${DIR}"/bbank2.syx -O sysex/voice/000087_bbank2.syx
+wget -c "${DIR}"/bell1.syx -O sysex/voice/000088_bell1.syx
+wget -c "${DIR}"/bells.syx -O sysex/voice/000089_bells.syx
+wget -c "${DIR}"/bells_01.syx -O sysex/voice/000090_bells_01.syx
+wget -c "${DIR}"/bells_02.syx -O sysex/voice/000091_bells_02.syx
+wget -c "${DIR}"/bells_03.syx -O sysex/voice/000092_bells_03.syx
+wget -c "${DIR}"/belltel.syx -O sysex/voice/000093_belltel.syx
+wget -c "${DIR}"/blanks.syx -O sysex/voice/000094_blanks.syx
+wget -c "${DIR}"/boruff.syx -O sysex/voice/000095_boruff.syx
+wget -c "${DIR}"/brass.syx -O sysex/voice/000096_brass.syx
+wget -c "${DIR}"/brass2.syx -O sysex/voice/000097_brass2.syx
+wget -c "${DIR}"/brass3.syx -O sysex/voice/000098_brass3.syx
+wget -c "${DIR}"/brass_01.syx -O sysex/voice/000099_brass_01.syx
+wget -c "${DIR}"/brass_02.syx -O sysex/voice/000100_brass_02.syx
+wget -c "${DIR}"/brass_03.syx -O sysex/voice/000101_brass_03.syx
+wget -c "${DIR}"/brass_04.syx -O sysex/voice/000102_brass_04.syx
+wget -c "${DIR}"/brass_05.syx -O sysex/voice/000103_brass_05.syx
+wget -c "${DIR}"/brass_06.syx -O sysex/voice/000104_brass_06.syx
+wget -c "${DIR}"/brass_07.syx -O sysex/voice/000105_brass_07.syx
+wget -c "${DIR}"/brass_08.syx -O sysex/voice/000106_brass_08.syx
+wget -c "${DIR}"/brass_09.syx -O sysex/voice/000107_brass_09.syx
+wget -c "${DIR}"/brass_10.syx -O sysex/voice/000108_brass_10.syx
+wget -c "${DIR}"/brass_11.syx -O sysex/voice/000109_brass_11.syx
+wget -c "${DIR}"/brass_12.syx -O sysex/voice/000110_brass_12.syx
+wget -c "${DIR}"/brass_13.syx -O sysex/voice/000111_brass_13.syx
+wget -c "${DIR}"/brass_14.syx -O sysex/voice/000112_brass_14.syx
+wget -c "${DIR}"/brass_15.syx -O sysex/voice/000113_brass_15.syx
+wget -c "${DIR}"/brass_16.syx -O sysex/voice/000114_brass_16.syx
+wget -c "${DIR}"/brass_17.syx -O sysex/voice/000115_brass_17.syx
+wget -c "${DIR}"/brass_18.syx -O sysex/voice/000116_brass_18.syx
+wget -c "${DIR}"/bstx.syx -O sysex/voice/000117_bstx.syx
+wget -c "${DIR}"/buck-1.syx -O sysex/voice/000118_buck-1.syx
+wget -c "${DIR}"/buck-2.syx -O sysex/voice/000119_buck-2.syx
+wget -c "${DIR}"/c-lab_1.syx -O sysex/voice/000120_c-lab_1.syx
+wget -c "${DIR}"/cello_01.syx -O sysex/voice/000121_cello_01.syx
+wget -c "${DIR}"/cello_02.syx -O sysex/voice/000122_cello_02.syx
+wget -c "${DIR}"/church.syx -O sysex/voice/000123_church.syx
+wget -c "${DIR}"/ciani.syx -O sysex/voice/000124_ciani.syx
+wget -c "${DIR}"/clang1.syx -O sysex/voice/000125_clang1.syx
+wget -c "${DIR}"/clarinet.syx -O sysex/voice/000126_clarinet.syx
+wget -c "${DIR}"/claude.syx -O sysex/voice/000127_claude.syx
+wget -c "${DIR}"/clav1.syx -O sysex/voice/000128_clav1.syx
+wget -c "${DIR}"/clav_01.syx -O sysex/voice/000129_clav_01.syx
+wget -c "${DIR}"/clav_02.syx -O sysex/voice/000130_clav_02.syx
+wget -c "${DIR}"/clav_03.syx -O sysex/voice/000131_clav_03.syx
+wget -c "${DIR}"/clav_04.syx -O sysex/voice/000132_clav_04.syx
+wget -c "${DIR}"/clav_05.syx -O sysex/voice/000133_clav_05.syx
+wget -c "${DIR}"/clav_06.syx -O sysex/voice/000134_clav_06.syx
+wget -c "${DIR}"/clavs.syx -O sysex/voice/000135_clavs.syx
+wget -c "${DIR}"/combo.syx -O sysex/voice/000136_combo.syx
+wget -c "${DIR}"/compuerr.syx -O sysex/voice/000137_compuerr.syx
+wget -c "${DIR}"/contemp.syx -O sysex/voice/000138_contemp.syx
+wget -c "${DIR}"/country.syx -O sysex/voice/000139_country.syx
+wget -c "${DIR}"/czeiszpe.syx -O sysex/voice/000140_czeiszpe.syx
+wget -c "${DIR}"/dave1.syx -O sysex/voice/000141_dave1.syx
+wget -c "${DIR}"/deckard.syx -O sysex/voice/000142_deckard.syx
+wget -c "${DIR}"/dg1.syx -O sysex/voice/000143_dg1.syx
+wget -c "${DIR}"/dg2.syx -O sysex/voice/000144_dg2.syx
+wget -c "${DIR}"/divers.syx -O sysex/voice/000145_divers.syx
+wget -c "${DIR}"/djw001.syx -O sysex/voice/000146_djw001.syx
+wget -c "${DIR}"/drm2.syx -O sysex/voice/000147_drm2.syx
+wget -c "${DIR}"/drm2a.syx -O sysex/voice/000148_drm2a.syx
+wget -c "${DIR}"/drmoct.syx -O sysex/voice/000149_drmoct.syx
+wget -c "${DIR}"/drt1.syx -O sysex/voice/000150_drt1.syx
+wget -c "${DIR}"/drt2.syx -O sysex/voice/000151_drt2.syx
+wget -c "${DIR}"/dx100.syx -O sysex/voice/000152_dx100.syx
+wget -c "${DIR}"/dx101.syx -O sysex/voice/000153_dx101.syx
+wget -c "${DIR}"/dx103.syx -O sysex/voice/000154_dx103.syx
+wget -c "${DIR}"/dx104.syx -O sysex/voice/000155_dx104.syx
+wget -c "${DIR}"/dx105.syx -O sysex/voice/000156_dx105.syx
+wget -c "${DIR}"/dx106.syx -O sysex/voice/000157_dx106.syx
+wget -c "${DIR}"/dx107.syx -O sysex/voice/000158_dx107.syx
+wget -c "${DIR}"/dx109.syx -O sysex/voice/000159_dx109.syx
+wget -c "${DIR}"/dx110.syx -O sysex/voice/000160_dx110.syx
+wget -c "${DIR}"/dx111.syx -O sysex/voice/000161_dx111.syx
+wget -c "${DIR}"/dx112.syx -O sysex/voice/000162_dx112.syx
+wget -c "${DIR}"/dx113.syx -O sysex/voice/000163_dx113.syx
+wget -c "${DIR}"/dx114.syx -O sysex/voice/000164_dx114.syx
+wget -c "${DIR}"/dx116.syx -O sysex/voice/000165_dx116.syx
+wget -c "${DIR}"/dx117.syx -O sysex/voice/000166_dx117.syx
+wget -c "${DIR}"/dx118.syx -O sysex/voice/000167_dx118.syx
+wget -c "${DIR}"/dx119.syx -O sysex/voice/000168_dx119.syx
+wget -c "${DIR}"/dx120.syx -O sysex/voice/000169_dx120.syx
+wget -c "${DIR}"/dx121.syx -O sysex/voice/000170_dx121.syx
+wget -c "${DIR}"/dx122.syx -O sysex/voice/000171_dx122.syx
+wget -c "${DIR}"/dx123.syx -O sysex/voice/000172_dx123.syx
+wget -c "${DIR}"/dx124.syx -O sysex/voice/000173_dx124.syx
+wget -c "${DIR}"/dx7bank.syx -O sysex/voice/000174_dx7bank.syx
+wget -c "${DIR}"/dx9.syx -O sysex/voice/000175_dx9.syx
+wget -c "${DIR}"/dxbasic5.syx -O sysex/voice/000176_dxbasic5.syx
+wget -c "${DIR}"/dxdxmi.syx -O sysex/voice/000177_dxdxmi.syx
+wget -c "${DIR}"/dxmik2.syx -O sysex/voice/000178_dxmik2.syx
+wget -c "${DIR}"/dxoc01.syx -O sysex/voice/000179_dxoc01.syx
+wget -c "${DIR}"/dxoc02.syx -O sysex/voice/000180_dxoc02.syx
+wget -c "${DIR}"/dxoc03.syx -O sysex/voice/000181_dxoc03.syx
+wget -c "${DIR}"/dxoc04.syx -O sysex/voice/000182_dxoc04.syx
+wget -c "${DIR}"/dxoc05.syx -O sysex/voice/000183_dxoc05.syx
+wget -c "${DIR}"/dxoc06.syx -O sysex/voice/000184_dxoc06.syx
+wget -c "${DIR}"/dxoc07.syx -O sysex/voice/000185_dxoc07.syx
+wget -c "${DIR}"/dxoc08.syx -O sysex/voice/000186_dxoc08.syx
+wget -c "${DIR}"/dxoc09.syx -O sysex/voice/000187_dxoc09.syx
+wget -c "${DIR}"/dxoc10.syx -O sysex/voice/000188_dxoc10.syx
+wget -c "${DIR}"/dxoc11.syx -O sysex/voice/000189_dxoc11.syx
+wget -c "${DIR}"/dxoc12.syx -O sysex/voice/000190_dxoc12.syx
+wget -c "${DIR}"/dxoc13.syx -O sysex/voice/000191_dxoc13.syx
+wget -c "${DIR}"/dxoc14.syx -O sysex/voice/000192_dxoc14.syx
+wget -c "${DIR}"/dxoc15.syx -O sysex/voice/000193_dxoc15.syx
+wget -c "${DIR}"/dxoc16.syx -O sysex/voice/000194_dxoc16.syx
+wget -c "${DIR}"/dxoc17.syx -O sysex/voice/000195_dxoc17.syx
+wget -c "${DIR}"/dxoc18.syx -O sysex/voice/000196_dxoc18.syx
+wget -c "${DIR}"/dxoc19.syx -O sysex/voice/000197_dxoc19.syx
+wget -c "${DIR}"/dxoc20.syx -O sysex/voice/000198_dxoc20.syx
+wget -c "${DIR}"/dxoc21.syx -O sysex/voice/000199_dxoc21.syx
+wget -c "${DIR}"/dxoc22.syx -O sysex/voice/000200_dxoc22.syx
+wget -c "${DIR}"/dxoc23.syx -O sysex/voice/000201_dxoc23.syx
+wget -c "${DIR}"/dxoc24.syx -O sysex/voice/000202_dxoc24.syx
+wget -c "${DIR}"/dxoc25.syx -O sysex/voice/000203_dxoc25.syx
+wget -c "${DIR}"/dxoc26.syx -O sysex/voice/000204_dxoc26.syx
+wget -c "${DIR}"/dxoc27.syx -O sysex/voice/000205_dxoc27.syx
+wget -c "${DIR}"/dxoc28.syx -O sysex/voice/000206_dxoc28.syx
+wget -c "${DIR}"/dxoc29.syx -O sysex/voice/000207_dxoc29.syx
+wget -c "${DIR}"/dxoc30.syx -O sysex/voice/000208_dxoc30.syx
+wget -c "${DIR}"/dxorgans.syx -O sysex/voice/000209_dxorgans.syx
+wget -c "${DIR}"/dxpluk.syx -O sysex/voice/000210_dxpluk.syx
+wget -c "${DIR}"/effect-1.syx -O sysex/voice/000211_effect-1.syx
+wget -c "${DIR}"/effect-2.syx -O sysex/voice/000212_effect-2.syx
+wget -c "${DIR}"/effects1.syx -O sysex/voice/000213_effects1.syx
+wget -c "${DIR}"/effects2.syx -O sysex/voice/000214_effects2.syx
+wget -c "${DIR}"/effects3.syx -O sysex/voice/000215_effects3.syx
+wget -c "${DIR}"/effects4.syx -O sysex/voice/000216_effects4.syx
+wget -c "${DIR}"/effects5.syx -O sysex/voice/000217_effects5.syx
+wget -c "${DIR}"/effects6.syx -O sysex/voice/000218_effects6.syx
+wget -c "${DIR}"/effects7.syx -O sysex/voice/000219_effects7.syx
+wget -c "${DIR}"/effects8.syx -O sysex/voice/000220_effects8.syx
+wget -c "${DIR}"/efx.syx -O sysex/voice/000221_efx.syx
+wget -c "${DIR}"/esipa.syx -O sysex/voice/000222_esipa.syx
+wget -c "${DIR}"/ethnic.syx -O sysex/voice/000223_ethnic.syx
+wget -c "${DIR}"/fatstuff.syx -O sysex/voice/000224_fatstuff.syx
+wget -c "${DIR}"/flute.syx -O sysex/voice/000225_flute.syx
+wget -c "${DIR}"/foo.syx -O sysex/voice/000226_foo.syx
+wget -c "${DIR}"/gig-1.syx -O sysex/voice/000227_gig-1.syx
+wget -c "${DIR}"/gregeea.syx -O sysex/voice/000228_gregeea.syx
+wget -c "${DIR}"/gregeeb.syx -O sysex/voice/000229_gregeeb.syx
+wget -c "${DIR}"/gregeec.syx -O sysex/voice/000230_gregeec.syx
+wget -c "${DIR}"/gregeed.syx -O sysex/voice/000231_gregeed.syx
+wget -c "${DIR}"/gtrs_01.syx -O sysex/voice/000232_gtrs_01.syx
+wget -c "${DIR}"/gtrs_a-d.syx -O sysex/voice/000233_gtrs_a-d.syx
+wget -c "${DIR}"/gtrs_d.syx -O sysex/voice/000234_gtrs_d.syx
+wget -c "${DIR}"/gtrs_el.syx -O sysex/voice/000235_gtrs_el.syx
+wget -c "${DIR}"/gtrs_g-j.syx -O sysex/voice/000236_gtrs_g-j.syx
+wget -c "${DIR}"/gtrs_j-k.syx -O sysex/voice/000237_gtrs_j-k.syx
+wget -c "${DIR}"/gtrs_l-n.syx -O sysex/voice/000238_gtrs_l-n.syx
+wget -c "${DIR}"/gtrs_n-r.syx -O sysex/voice/000239_gtrs_n-r.syx
+wget -c "${DIR}"/gtrs_s-v.syx -O sysex/voice/000240_gtrs_s-v.syx
+wget -c "${DIR}"/gtrsonus.syx -O sysex/voice/000241_gtrsonus.syx
+wget -c "${DIR}"/guitar1.syx -O sysex/voice/000242_guitar1.syx
+wget -c "${DIR}"/guitar2.syx -O sysex/voice/000243_guitar2.syx
+wget -c "${DIR}"/harmonic.syx -O sysex/voice/000244_harmonic.syx
+wget -c "${DIR}"/harp_1.syx -O sysex/voice/000245_harp_1.syx
+wget -c "${DIR}"/harp_2.syx -O sysex/voice/000246_harp_2.syx
+wget -c "${DIR}"/harpsi_1.syx -O sysex/voice/000247_harpsi_1.syx
+wget -c "${DIR}"/harpsi_2.syx -O sysex/voice/000248_harpsi_2.syx
+wget -c "${DIR}"/italian2.syx -O sysex/voice/000249_italian2.syx
+wget -c "${DIR}"/italian3.syx -O sysex/voice/000250_italian3.syx
+wget -c "${DIR}"/jb001.syx -O sysex/voice/000251_jb001.syx
+wget -c "${DIR}"/jb002.syx -O sysex/voice/000252_jb002.syx
+wget -c "${DIR}"/jfd001.syx -O sysex/voice/000253_jfd001.syx
+wget -c "${DIR}"/keybds01.syx -O sysex/voice/000254_keybds01.syx
+wget -c "${DIR}"/keyboard.syx -O sysex/voice/000255_keyboard.syx
+wget -c "${DIR}"/king.syx -O sysex/voice/000256_king.syx
+wget -c "${DIR}"/koto.syx -O sysex/voice/000257_koto.syx
+wget -c "${DIR}"/kq_sampl.syx -O sysex/voice/000258_kq_sampl.syx
+wget -c "${DIR}"/laser.syx -O sysex/voice/000259_laser.syx
+wget -c "${DIR}"/magazine.syx -O sysex/voice/000260_magazine.syx
+wget -c "${DIR}"/mallets1.syx -O sysex/voice/000261_mallets1.syx
+wget -c "${DIR}"/mallets2.syx -O sysex/voice/000262_mallets2.syx
+wget -c "${DIR}"/massey.syx -O sysex/voice/000263_massey.syx
+wget -c "${DIR}"/metal.syx -O sysex/voice/000264_metal.syx
+wget -c "${DIR}"/mf.syx -O sysex/voice/000265_mf.syx
+wget -c "${DIR}"/misc_01.syx -O sysex/voice/000266_misc_01.syx
+wget -c "${DIR}"/misc_02.syx -O sysex/voice/000267_misc_02.syx
+wget -c "${DIR}"/misc_03.syx -O sysex/voice/000268_misc_03.syx
+wget -c "${DIR}"/misc_04.syx -O sysex/voice/000269_misc_04.syx
+wget -c "${DIR}"/misc_05.syx -O sysex/voice/000270_misc_05.syx
+wget -c "${DIR}"/misc_06.syx -O sysex/voice/000271_misc_06.syx
+wget -c "${DIR}"/misc_07.syx -O sysex/voice/000272_misc_07.syx
+wget -c "${DIR}"/misc_08.syx -O sysex/voice/000273_misc_08.syx
+wget -c "${DIR}"/misc_09.syx -O sysex/voice/000274_misc_09.syx
+wget -c "${DIR}"/misc_10.syx -O sysex/voice/000275_misc_10.syx
+wget -c "${DIR}"/misc_11.syx -O sysex/voice/000276_misc_11.syx
+wget -c "${DIR}"/misc_12.syx -O sysex/voice/000277_misc_12.syx
+wget -c "${DIR}"/misc_13.syx -O sysex/voice/000278_misc_13.syx
+wget -c "${DIR}"/misc_14.syx -O sysex/voice/000279_misc_14.syx
+wget -c "${DIR}"/misc_15.syx -O sysex/voice/000280_misc_15.syx
+wget -c "${DIR}"/misc_16.syx -O sysex/voice/000281_misc_16.syx
+wget -c "${DIR}"/misc_17.syx -O sysex/voice/000282_misc_17.syx
+wget -c "${DIR}"/misc_18.syx -O sysex/voice/000283_misc_18.syx
+wget -c "${DIR}"/misc_19.syx -O sysex/voice/000284_misc_19.syx
+wget -c "${DIR}"/misc_20.syx -O sysex/voice/000285_misc_20.syx
+wget -c "${DIR}"/misc_21.syx -O sysex/voice/000286_misc_21.syx
+wget -c "${DIR}"/misc_22.syx -O sysex/voice/000287_misc_22.syx
+wget -c "${DIR}"/misc_23.syx -O sysex/voice/000288_misc_23.syx
+wget -c "${DIR}"/misc_24.syx -O sysex/voice/000289_misc_24.syx
+wget -c "${DIR}"/misc_25.syx -O sysex/voice/000290_misc_25.syx
+wget -c "${DIR}"/misc_26.syx -O sysex/voice/000291_misc_26.syx
+wget -c "${DIR}"/misc_27.syx -O sysex/voice/000292_misc_27.syx
+wget -c "${DIR}"/misc_28.syx -O sysex/voice/000293_misc_28.syx
+wget -c "${DIR}"/misc_29.syx -O sysex/voice/000294_misc_29.syx
+wget -c "${DIR}"/misc_30.syx -O sysex/voice/000295_misc_30.syx
+wget -c "${DIR}"/misc_31.syx -O sysex/voice/000296_misc_31.syx
+wget -c "${DIR}"/misc_32.syx -O sysex/voice/000297_misc_32.syx
+wget -c "${DIR}"/misc_33.syx -O sysex/voice/000298_misc_33.syx
+wget -c "${DIR}"/misc_34.syx -O sysex/voice/000299_misc_34.syx
+wget -c "${DIR}"/mjfdx7a.syx -O sysex/voice/000300_mjfdx7a.syx
+wget -c "${DIR}"/mjfdx7b.syx -O sysex/voice/000301_mjfdx7b.syx
+wget -c "${DIR}"/mjfdx7c.syx -O sysex/voice/000302_mjfdx7c.syx
+wget -c "${DIR}"/mjfdx7d.syx -O sysex/voice/000303_mjfdx7d.syx
+wget -c "${DIR}"/mjfdx7e.syx -O sysex/voice/000304_mjfdx7e.syx
+wget -c "${DIR}"/mjfdx7f.syx -O sysex/voice/000305_mjfdx7f.syx
+wget -c "${DIR}"/mjfdx7g.syx -O sysex/voice/000306_mjfdx7g.syx
+wget -c "${DIR}"/mjfdx7h.syx -O sysex/voice/000307_mjfdx7h.syx
+wget -c "${DIR}"/monteleo.syx -O sysex/voice/000308_monteleo.syx
+wget -c "${DIR}"/moog.syx -O sysex/voice/000309_moog.syx
+wget -c "${DIR}"/mortega.syx -O sysex/voice/000310_mortega.syx
+wget -c "${DIR}"/newsnd.syx -O sysex/voice/000311_newsnd.syx
+wget -c "${DIR}"/oboe_bas.syx -O sysex/voice/000312_oboe_bas.syx
+wget -c "${DIR}"/orch_1.syx -O sysex/voice/000313_orch_1.syx
+wget -c "${DIR}"/orchestr.syx -O sysex/voice/000314_orchestr.syx
+wget -c "${DIR}"/org_clav.syx -O sysex/voice/000315_org_clav.syx
+wget -c "${DIR}"/organ1.syx -O sysex/voice/000316_organ1.syx
+wget -c "${DIR}"/organ2.syx -O sysex/voice/000317_organ2.syx
+wget -c "${DIR}"/organ3.syx -O sysex/voice/000318_organ3.syx
+wget -c "${DIR}"/organ_01.syx -O sysex/voice/000319_organ_01.syx
+wget -c "${DIR}"/organ_02.syx -O sysex/voice/000320_organ_02.syx
+wget -c "${DIR}"/organ_03.syx -O sysex/voice/000321_organ_03.syx
+wget -c "${DIR}"/organ_04.syx -O sysex/voice/000322_organ_04.syx
+wget -c "${DIR}"/organ_05.syx -O sysex/voice/000323_organ_05.syx
+wget -c "${DIR}"/organ_06.syx -O sysex/voice/000324_organ_06.syx
+wget -c "${DIR}"/organ_07.syx -O sysex/voice/000325_organ_07.syx
+wget -c "${DIR}"/organ_08.syx -O sysex/voice/000326_organ_08.syx
+wget -c "${DIR}"/organ_b3.syx -O sysex/voice/000327_organ_b3.syx
+wget -c "${DIR}"/organham.syx -O sysex/voice/000328_organham.syx
+wget -c "${DIR}"/orgpipe1.syx -O sysex/voice/000329_orgpipe1.syx
+wget -c "${DIR}"/orgpipe2.syx -O sysex/voice/000330_orgpipe2.syx
+wget -c "${DIR}"/patches.syx -O sysex/voice/000331_patches.syx
+wget -c "${DIR}"/pddx701a.syx -O sysex/voice/000332_pddx701a.syx
+wget -c "${DIR}"/pddx701b.syx -O sysex/voice/000333_pddx701b.syx
+wget -c "${DIR}"/pddx701c.syx -O sysex/voice/000334_pddx701c.syx
+wget -c "${DIR}"/pddx701d.syx -O sysex/voice/000335_pddx701d.syx
+wget -c "${DIR}"/pearson.syx -O sysex/voice/000336_pearson.syx
+wget -c "${DIR}"/pedanna.syx -O sysex/voice/000337_pedanna.syx
+wget -c "${DIR}"/perc1.syx -O sysex/voice/000338_perc1.syx
+wget -c "${DIR}"/perc2.syx -O sysex/voice/000339_perc2.syx
+wget -c "${DIR}"/perc_a.syx -O sysex/voice/000340_perc_a.syx
+wget -c "${DIR}"/perc_b.syx -O sysex/voice/000341_perc_b.syx
+wget -c "${DIR}"/percus01.syx -O sysex/voice/000342_percus01.syx
+wget -c "${DIR}"/percus02.syx -O sysex/voice/000343_percus02.syx
+wget -c "${DIR}"/percus03.syx -O sysex/voice/000344_percus03.syx
+wget -c "${DIR}"/percus04.syx -O sysex/voice/000345_percus04.syx
+wget -c "${DIR}"/percus05.syx -O sysex/voice/000346_percus05.syx
+wget -c "${DIR}"/percus06.syx -O sysex/voice/000347_percus06.syx
+wget -c "${DIR}"/percus07.syx -O sysex/voice/000348_percus07.syx
+wget -c "${DIR}"/percus08.syx -O sysex/voice/000349_percus08.syx
+wget -c "${DIR}"/percus09.syx -O sysex/voice/000350_percus09.syx
+wget -c "${DIR}"/percus10.syx -O sysex/voice/000351_percus10.syx
+wget -c "${DIR}"/percvibe.syx -O sysex/voice/000352_percvibe.syx
+wget -c "${DIR}"/personus.syx -O sysex/voice/000353_personus.syx
+wget -c "${DIR}"/piano1.syx -O sysex/voice/000354_piano1.syx
+wget -c "${DIR}"/piano_01.syx -O sysex/voice/000355_piano_01.syx
+wget -c "${DIR}"/piano_02.syx -O sysex/voice/000356_piano_02.syx
+wget -c "${DIR}"/piano_03.syx -O sysex/voice/000357_piano_03.syx
+wget -c "${DIR}"/piano_04.syx -O sysex/voice/000358_piano_04.syx
+wget -c "${DIR}"/piano_05.syx -O sysex/voice/000359_piano_05.syx
+wget -c "${DIR}"/piano_06.syx -O sysex/voice/000360_piano_06.syx
+wget -c "${DIR}"/piano_07.syx -O sysex/voice/000361_piano_07.syx
+wget -c "${DIR}"/piano_08.syx -O sysex/voice/000362_piano_08.syx
+wget -c "${DIR}"/piano_09.syx -O sysex/voice/000363_piano_09.syx
+wget -c "${DIR}"/piano_10.syx -O sysex/voice/000364_piano_10.syx
+wget -c "${DIR}"/piano_11.syx -O sysex/voice/000365_piano_11.syx
+wget -c "${DIR}"/piano_12.syx -O sysex/voice/000366_piano_12.syx
+wget -c "${DIR}"/piano_13.syx -O sysex/voice/000367_piano_13.syx
+wget -c "${DIR}"/piano_a1.syx -O sysex/voice/000368_piano_a1.syx
+wget -c "${DIR}"/piano_e1.syx -O sysex/voice/000369_piano_e1.syx
+wget -c "${DIR}"/piano_e2.syx -O sysex/voice/000370_piano_e2.syx
+wget -c "${DIR}"/piano_e3.syx -O sysex/voice/000371_piano_e3.syx
+wget -c "${DIR}"/piano_e4.syx -O sysex/voice/000372_piano_e4.syx
+wget -c "${DIR}"/piano_e5.syx -O sysex/voice/000373_piano_e5.syx
+wget -c "${DIR}"/plucked.syx -O sysex/voice/000374_plucked.syx
+wget -c "${DIR}"/powerply.syx -O sysex/voice/000375_powerply.syx
+wget -c "${DIR}"/pr01.syx -O sysex/voice/000376_pr01.syx
+wget -c "${DIR}"/pr02.syx -O sysex/voice/000377_pr02.syx
+wget -c "${DIR}"/pr03.syx -O sysex/voice/000378_pr03.syx
+wget -c "${DIR}"/pro2.syx -O sysex/voice/000379_pro2.syx
+wget -c "${DIR}"/ram_bank.syx -O sysex/voice/000380_ram_bank.syx
+wget -c "${DIR}"/ram_cart.syx -O sysex/voice/000381_ram_cart.syx
+wget -c "${DIR}"/rambank1.syx -O sysex/voice/000382_rambank1.syx
+wget -c "${DIR}"/ramcart.syx -O sysex/voice/000383_ramcart.syx
+wget -c "${DIR}"/ramcartp.syx -O sysex/voice/000384_ramcartp.syx
+wget -c "${DIR}"/ramnbank.syx -O sysex/voice/000385_ramnbank.syx
+wget -c "${DIR}"/ray-1.syx -O sysex/voice/000386_ray-1.syx
+wget -c "${DIR}"/ray-10.syx -O sysex/voice/000387_ray-10.syx
+wget -c "${DIR}"/ray-11.syx -O sysex/voice/000388_ray-11.syx
+wget -c "${DIR}"/ray-12.syx -O sysex/voice/000389_ray-12.syx
+wget -c "${DIR}"/ray-13.syx -O sysex/voice/000390_ray-13.syx
+wget -c "${DIR}"/ray-14.syx -O sysex/voice/000391_ray-14.syx
+wget -c "${DIR}"/ray-15.syx -O sysex/voice/000392_ray-15.syx
+wget -c "${DIR}"/ray-16.syx -O sysex/voice/000393_ray-16.syx
+wget -c "${DIR}"/ray-17.syx -O sysex/voice/000394_ray-17.syx
+wget -c "${DIR}"/ray-18.syx -O sysex/voice/000395_ray-18.syx
+wget -c "${DIR}"/ray-19.syx -O sysex/voice/000396_ray-19.syx
+wget -c "${DIR}"/ray-2.syx -O sysex/voice/000397_ray-2.syx
+wget -c "${DIR}"/ray-20.syx -O sysex/voice/000398_ray-20.syx
+wget -c "${DIR}"/ray-21.syx -O sysex/voice/000399_ray-21.syx
+wget -c "${DIR}"/ray-3.syx -O sysex/voice/000400_ray-3.syx
+wget -c "${DIR}"/ray-4.syx -O sysex/voice/000401_ray-4.syx
+wget -c "${DIR}"/ray-5.syx -O sysex/voice/000402_ray-5.syx
+wget -c "${DIR}"/ray-6.syx -O sysex/voice/000403_ray-6.syx
+wget -c "${DIR}"/ray-7.syx -O sysex/voice/000404_ray-7.syx
+wget -c "${DIR}"/ray-8.syx -O sysex/voice/000405_ray-8.syx
+wget -c "${DIR}"/ray-9.syx -O sysex/voice/000406_ray-9.syx
+wget -c "${DIR}"/rhodes1.syx -O sysex/voice/000407_rhodes1.syx
+wget -c "${DIR}"/rhodes2.syx -O sysex/voice/000408_rhodes2.syx
+wget -c "${DIR}"/rlegnini.syx -O sysex/voice/000409_rlegnini.syx
+wget -c "${DIR}"/rm0001.syx -O sysex/voice/000410_rm0001.syx
+wget -c "${DIR}"/rom-1.syx -O sysex/voice/000411_rom-1.syx
+wget -c "${DIR}"/rom-2.syx -O sysex/voice/000412_rom-2.syx
+wget -c "${DIR}"/rom-3.syx -O sysex/voice/000413_rom-3.syx
+wget -c "${DIR}"/rom-4.syx -O sysex/voice/000414_rom-4.syx
+wget -c "${DIR}"/sax_01.syx -O sysex/voice/000415_sax_01.syx
+wget -c "${DIR}"/sax_02.syx -O sysex/voice/000416_sax_02.syx
+wget -c "${DIR}"/sitar.syx -O sysex/voice/000417_sitar.syx
+wget -c "${DIR}"/solange.syx -O sysex/voice/000418_solange.syx
+wget -c "${DIR}"/solange0.syx -O sysex/voice/000419_solange0.syx
+wget -c "${DIR}"/solange1.syx -O sysex/voice/000420_solange1.syx
+wget -c "${DIR}"/solange2.syx -O sysex/voice/000421_solange2.syx
+wget -c "${DIR}"/solange3.syx -O sysex/voice/000422_solange3.syx
+wget -c "${DIR}"/solange4.syx -O sysex/voice/000423_solange4.syx
+wget -c "${DIR}"/solange5.syx -O sysex/voice/000424_solange5.syx
+wget -c "${DIR}"/solange6.syx -O sysex/voice/000425_solange6.syx
+wget -c "${DIR}"/sonus1.syx -O sysex/voice/000426_sonus1.syx
+wget -c "${DIR}"/spangler.syx -O sysex/voice/000427_spangler.syx
+wget -c "${DIR}"/splits.syx -O sysex/voice/000428_splits.syx
+wget -c "${DIR}"/starma.syx -O sysex/voice/000429_starma.syx
+wget -c "${DIR}"/steinber.syx -O sysex/voice/000430_steinber.syx
+wget -c "${DIR}"/steph1.syx -O sysex/voice/000431_steph1.syx
+wget -c "${DIR}"/steph2.syx -O sysex/voice/000432_steph2.syx
+wget -c "${DIR}"/steph3.syx -O sysex/voice/000433_steph3.syx
+wget -c "${DIR}"/steph4.syx -O sysex/voice/000434_steph4.syx
+wget -c "${DIR}"/steve.syx -O sysex/voice/000435_steve.syx
+wget -c "${DIR}"/string1.syx -O sysex/voice/000436_string1.syx
+wget -c "${DIR}"/string2.syx -O sysex/voice/000437_string2.syx
+wget -c "${DIR}"/stringb.syx -O sysex/voice/000438_stringb.syx
+wget -c "${DIR}"/strnga-a.syx -O sysex/voice/000439_strnga-a.syx
+wget -c "${DIR}"/strnga-b.syx -O sysex/voice/000440_strnga-b.syx
+wget -c "${DIR}"/strngb-d.syx -O sysex/voice/000441_strngb-d.syx
+wget -c "${DIR}"/strngd-h.syx -O sysex/voice/000442_strngd-h.syx
+wget -c "${DIR}"/strngh-k.syx -O sysex/voice/000443_strngh-k.syx
+wget -c "${DIR}"/strngk-o.syx -O sysex/voice/000444_strngk-o.syx
+wget -c "${DIR}"/strngs01.syx -O sysex/voice/000445_strngs01.syx
+wget -c "${DIR}"/strngs02.syx -O sysex/voice/000446_strngs02.syx
+wget -c "${DIR}"/strngs03.syx -O sysex/voice/000447_strngs03.syx
+wget -c "${DIR}"/strngs04.syx -O sysex/voice/000448_strngs04.syx
+wget -c "${DIR}"/strngs05.syx -O sysex/voice/000449_strngs05.syx
+wget -c "${DIR}"/strngs06.syx -O sysex/voice/000450_strngs06.syx
+wget -c "${DIR}"/strngs07.syx -O sysex/voice/000451_strngs07.syx
+wget -c "${DIR}"/strngs08.syx -O sysex/voice/000452_strngs08.syx
+wget -c "${DIR}"/strngs09.syx -O sysex/voice/000453_strngs09.syx
+wget -c "${DIR}"/strngs10.syx -O sysex/voice/000454_strngs10.syx
+wget -c "${DIR}"/strngs12.syx -O sysex/voice/000455_strngs12.syx
+wget -c "${DIR}"/strngs13.syx -O sysex/voice/000456_strngs13.syx
+wget -c "${DIR}"/strngs14.syx -O sysex/voice/000457_strngs14.syx
+wget -c "${DIR}"/strngs15.syx -O sysex/voice/000458_strngs15.syx
+wget -c "${DIR}"/strngs16.syx -O sysex/voice/000459_strngs16.syx
+wget -c "${DIR}"/strngs17.syx -O sysex/voice/000460_strngs17.syx
+wget -c "${DIR}"/strngs18.syx -O sysex/voice/000461_strngs18.syx
+wget -c "${DIR}"/strngs19.syx -O sysex/voice/000462_strngs19.syx
+wget -c "${DIR}"/strngs20.syx -O sysex/voice/000463_strngs20.syx
+wget -c "${DIR}"/sustain1.syx -O sysex/voice/000464_sustain1.syx
+wget -c "${DIR}"/synth_01.syx -O sysex/voice/000465_synth_01.syx
+wget -c "${DIR}"/synth_02.syx -O sysex/voice/000466_synth_02.syx
+wget -c "${DIR}"/synth_03.syx -O sysex/voice/000467_synth_03.syx
+wget -c "${DIR}"/synth_04.syx -O sysex/voice/000468_synth_04.syx
+wget -c "${DIR}"/synth_05.syx -O sysex/voice/000469_synth_05.syx
+wget -c "${DIR}"/synth_06.syx -O sysex/voice/000470_synth_06.syx
+wget -c "${DIR}"/synth_07.syx -O sysex/voice/000471_synth_07.syx
+wget -c "${DIR}"/synth_08.syx -O sysex/voice/000472_synth_08.syx
+wget -c "${DIR}"/synth_09.syx -O sysex/voice/000473_synth_09.syx
+wget -c "${DIR}"/synth_10.syx -O sysex/voice/000474_synth_10.syx
+wget -c "${DIR}"/synth_11.syx -O sysex/voice/000475_synth_11.syx
+wget -c "${DIR}"/synth_12.syx -O sysex/voice/000476_synth_12.syx
+wget -c "${DIR}"/synth_13.syx -O sysex/voice/000477_synth_13.syx
+wget -c "${DIR}"/synth_14.syx -O sysex/voice/000478_synth_14.syx
+wget -c "${DIR}"/synth_15.syx -O sysex/voice/000479_synth_15.syx
+wget -c "${DIR}"/synth_16.syx -O sysex/voice/000480_synth_16.syx
+wget -c "${DIR}"/synth_17.syx -O sysex/voice/000481_synth_17.syx
+wget -c "${DIR}"/synth_18.syx -O sysex/voice/000482_synth_18.syx
+wget -c "${DIR}"/synth_19.syx -O sysex/voice/000483_synth_19.syx
+wget -c "${DIR}"/synth_20.syx -O sysex/voice/000484_synth_20.syx
+wget -c "${DIR}"/synth_21.syx -O sysex/voice/000485_synth_21.syx
+wget -c "${DIR}"/synth_22.syx -O sysex/voice/000486_synth_22.syx
+wget -c "${DIR}"/synths.syx -O sysex/voice/000487_synths.syx
+wget -c "${DIR}"/syx_0628.syx -O sysex/voice/000488_syx_0628.syx
+wget -c "${DIR}"/textures.syx -O sysex/voice/000489_textures.syx
+wget -c "${DIR}"/tfi5.syx -O sysex/voice/000490_tfi5.syx
+wget -c "${DIR}"/tfi6.syx -O sysex/voice/000491_tfi6.syx
+wget -c "${DIR}"/tfi7.syx -O sysex/voice/000492_tfi7.syx
+wget -c "${DIR}"/tfi8.syx -O sysex/voice/000493_tfi8.syx
+wget -c "${DIR}"/tfrack01.syx -O sysex/voice/000494_tfrack01.syx
+wget -c "${DIR}"/tfrack02.syx -O sysex/voice/000495_tfrack02.syx
+wget -c "${DIR}"/theatre.syx -O sysex/voice/000496_theatre.syx
+wget -c "${DIR}"/things.syx -O sysex/voice/000497_things.syx
+wget -c "${DIR}"/trumpet.syx -O sysex/voice/000498_trumpet.syx
+wget -c "${DIR}"/tx7a.syx -O sysex/voice/000499_tx7a.syx
+wget -c "${DIR}"/violin_1.syx -O sysex/voice/000500_violin_1.syx
+wget -c "${DIR}"/voices_1.syx -O sysex/voice/000501_voices_1.syx
+wget -c "${DIR}"/voices_2.syx -O sysex/voice/000502_voices_2.syx
+wget -c "${DIR}"/voices_3.syx -O sysex/voice/000503_voices_3.syx
+wget -c "${DIR}"/voices_5.syx -O sysex/voice/000504_voices_5.syx
+wget -c "${DIR}"/voices_6.syx -O sysex/voice/000505_voices_6.syx
+wget -c "${DIR}"/voices_7.syx -O sysex/voice/000506_voices_7.syx
+wget -c "${DIR}"/voices_8.syx -O sysex/voice/000507_voices_8.syx
+wget -c "${DIR}"/voices_9.syx -O sysex/voice/000508_voices_9.syx
+wget -c "${DIR}"/weird1.syx -O sysex/voice/000509_weird1.syx
+wget -c "${DIR}"/weird2.syx -O sysex/voice/000510_weird2.syx
+wget -c "${DIR}"/weird3.syx -O sysex/voice/000511_weird3.syx
+wget -c "${DIR}"/wheatley.syx -O sysex/voice/000512_wheatley.syx
+wget -c "${DIR}"/white.syx -O sysex/voice/000513_white.syx
+wget -c "${DIR}"/wodwind1.syx -O sysex/voice/000514_wodwind1.syx
+wget -c "${DIR}"/wodwind2.syx -O sysex/voice/000515_wodwind2.syx
+wget -c "${DIR}"/wodwind3.syx -O sysex/voice/000516_wodwind3.syx
+wget -c "${DIR}"/wodwind4.syx -O sysex/voice/000517_wodwind4.syx
+wget -c "${DIR}"/wodwind5.syx -O sysex/voice/000518_wodwind5.syx
+wget -c "${DIR}"/wodwind6.syx -O sysex/voice/000519_wodwind6.syx
+wget -c "${DIR}"/woodwind.syx -O sysex/voice/000520_woodwind.syx
+wget -c "${DIR}"/wurlizer.syx -O sysex/voice/000521_wurlizer.syx
+wget -c "${DIR}"/wwind1.syx -O sysex/voice/000522_wwind1.syx
+wget -c "${DIR}"/wwind2.syx -O sysex/voice/000523_wwind2.syx
+wget -c "${DIR}"/wwind3.syx -O sysex/voice/000524_wwind3.syx
+wget -c "${DIR}"/wwind4.syx -O sysex/voice/000525_wwind4.syx
+wget -c "${DIR}"/wyatt.syx -O sysex/voice/000526_wyatt.syx
+wget -c "${DIR}"/xylos.syx -O sysex/voice/000527_xylos.syx
+wget -c "${DIR}"/yam-26.syx -O sysex/voice/000528_yam-26.syx
+wget -c "${DIR}"/yamaha.syx -O sysex/voice/000529_yamaha.syx
+wget -c "${DIR}"/zone3.syx -O sysex/voice/000530_zone3.syx
diff --git a/incrementalBuild.sh b/incrementalBuild.sh
new file mode 100644
index 0000000..6dd6a14
--- /dev/null
+++ b/incrementalBuild.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [ -z "${RPI}" ] ; then
+# echo "\$RPI missing, exting"
+# exit 1
+ export RPI=4
+fi
+
+if [ "${RPI}" -gt "2" ]; then
+ export TOOLCHAIN_PREFIX="aarch64-none-elf-"
+else
+ export TOOLCHAIN_PREFIX="arm-none-eabi-"
+fi
+
+# Define system options
+OPTIONS="-o USE_PWM_AUDIO_ON_ZERO -o SAVE_VFP_REGS_ON_IRQ -o REALTIME -o SCREEN_DMA_BURST_LENGTH=1"
+if [ "${RPI}" -gt "1" ]; then
+ OPTIONS="${OPTIONS} -o ARM_ALLOW_MULTI_CORE"
+fi
+
+# Build circle-stdlib library
+# cd circle-stdlib/
+# make mrproper || true
+# ./configure -r ${RPI} --prefix "${TOOLCHAIN_PREFIX}" ${OPTIONS} -o KERNEL_MAX_SIZE=0x400000
+# make -j
+
+# Build additional libraries
+# cd libs/circle/addon/display/
+# make clean || true
+# make -j
+# cd ../sensor/
+# make clean || true
+# make -j
+# cd ../Properties/
+# make clean || true
+# make -j
+# cd ../../../..
+
+# cd ..
+
+# Build MiniDexed
+cd src
+# make clean || true
+make -j
+ls *.img
+cd ..
diff --git a/rebuild.sh b/rebuild.sh
new file mode 100644
index 0000000..827d87f
--- /dev/null
+++ b/rebuild.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+set -x
+
+export RPI=4
+
+export PATH=$(readlink -f ./gcc-*/bin/):$PATH
+
+./incrementalBuild.sh
+cp ./src/kernel*.img ./kernels/
+
+# Make zip that contains Raspberry Pi 4 boot files. The contents can be copied to a FAT32 formatted partition on a microSD card
+cp -r ./circle-stdlib/libs/circle/boot/* sdcard
+rm -rf sdcard/config*.txt sdcard/README sdcard/Makefile sdcard/armstub sdcard/COPYING.linux
+cp ./src/config.txt ./src/minidexed.ini ./src/*img ./src/performance.ini sdcard/
+echo "usbspeed=full" > sdcard/cmdline.txt
+cd sdcard
+cp ../kernels/* . || true
+zip -r ../MiniDexed_$GITHUB_RUN_NUMBER_$(date +%Y-%m-%d).zip *
+cd -
+
+echo "DONE!!!"
\ No newline at end of file
diff --git a/setup_dev_env.sh b/setup_dev_env.sh
new file mode 100644
index 0000000..6457c7d
--- /dev/null
+++ b/setup_dev_env.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+# this script install the dev environment and assume that the repositorw is alreadw cloned
+
+# Choose your RPi
+export RPI=4
+
+#git clone https://github.com/probonopd/MiniDexed
+#cd MiniDexed
+mkdir -p kernels sdcard
+
+# Get develop branch of circle
+cd circle-stdlib/libs/circle
+git checkout ae22928 # develop
+cd -
+
+# Recursively pull git submodules
+git submodule update --init --recursive
+
+# Install toolchain
+if [ "${RPI}" -gt 2 ]
+then
+ wget 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
+else
+ wget 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
+fi
+tar xvf gcc-arm-*-*.tar.xz
+export PATH=$(readlink -f ./gcc-*/bin/):$PATH
+
+# Build dependencies and MiniDexed
+./build.sh
+cp ./src/kernel*.img ./kernels/
+
+# Get Raspberry Pi boot files
+cd ./circle-stdlib/libs/circle/boot
+make
+if [ "${RPI}" -gt 2 ]
+then
+ make armstub64
+fi
+cd -
+
+# Make zip that contains Raspberry Pi 4 boot files. The contents can be copied to a FAT32 formatted partition on a microSD card
+cd sdcard
+../getsysex.sh
+cd ..
+cp -r ./circle-stdlib/libs/circle/boot/* sdcard
+rm -rf sdcard/config*.txt sdcard/README sdcard/Makefile sdcard/armstub sdcard/COPYING.linux
+cp ./src/config.txt ./src/minidexed.ini ./src/*img ./src/performance.ini sdcard/
+echo "usbspeed=full" > sdcard/cmdline.txt
+cd sdcard
+cp ../kernels/* . || true
+zip -r ../MaxiDexed_$GITHUB_RUN_NUMBER_$(date +%Y-%m-%d).zip *
+cd -
+
+# # Optionally, create a RPi image. This can be written to a microSD card using tools like Etcher or dd
+# sudo apt install --yes mount parted
+# IMG="`date +%Y-%m-%d`_minidexed-RPi${RPI}.img"
+# dd of="${IMG}" seek=50MiB bs=1 count=0
+# sudo parted "${IMG}" mktable msdos
+# sudo parted "${IMG}" mkpart primary fat32 2048s 100%
+# DEV=`sudo losetup --find --partscan --show "${IMG}"`
+# sudo mkfs.vfat -F 32 -n BOOT "${DEV}p1"
+# mkdir boot
+# sudo mount "${DEV}p1" boot
+# sudo cp -R sdcard/* boot
+# sudo umount boot
+# sudo losetup -d "${DEV}"
+# rm -r boot
+
+# # Write to SD card
+# sudo dd if="${IMG}" of=/dev/mmcblk0 bs=512k status=progress && sync
\ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
index 3ea9c78..e983896 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -5,11 +5,29 @@
CIRCLE_STDLIB_DIR = ../circle-stdlib
SYNTH_DEXED_DIR = ../Synth_Dexed/src
CMSIS_DIR = ../CMSIS_5/CMSIS
+U8G2_DIR = ../u8g2
-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_compressor.o effect_platervbstereo.o
+BUILD_DIR = ../build
+BUILD_OBJ_DIR = $(BUILD_DIR)/objs
+
+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_compressor.o \
+ effect_platervbstereo.o \
+ ui.o \
+ screens.o \
+ userinterfaceext.o
OPTIMIZE = -O3
diff --git a/src/Rules.mk b/src/Rules.mk
index 39b9f25..5559f15 100644
--- a/src/Rules.mk
+++ b/src/Rules.mk
@@ -11,7 +11,9 @@ include $(CIRCLEHOME)/Rules.mk
INCLUDE += \
-I $(CIRCLE_STDLIB_DIR)/include \
- -I $(NEWLIBDIR)/include
+ -I $(NEWLIBDIR)/include \
+ -I $(U8H2_DIR)/csrc \
+ -I $(U8H2_DIR)/cppsrc
LIBS += \
$(NEWLIBDIR)/lib/libm.a \
diff --git a/src/Synth_Dexed.mk b/src/Synth_Dexed.mk
index 443d606..9309fed 100644
--- a/src/Synth_Dexed.mk
+++ b/src/Synth_Dexed.mk
@@ -9,6 +9,119 @@ CMSIS_DSP_COMPUTELIB_INCLUDE_DIR = $(CMSIS_DIR)/DSP/ComputeLibrary/Include
CMSIS_DSP_SOURCE_DIR = $(CMSIS_DIR)/DSP/Source
CMSIS_DSP_COMPUTELIB_SRC_DIR = $(CMSIS_DIR)/DSP/ComputeLibrary/Source
+U8G2_OBJS += \
+ $(U8G2_DIR)/cppsrc/U8g2lib.o \
+ $(U8G2_DIR)/csrc/mui.o \
+ $(U8G2_DIR)/csrc/mui_u8g2.o \
+ $(U8G2_DIR)/csrc/u8g2_bitmap.o \
+ $(U8G2_DIR)/csrc/u8g2_box.o \
+ $(U8G2_DIR)/csrc/u8g2_buffer.o \
+ $(U8G2_DIR)/csrc/u8g2_button.o \
+ $(U8G2_DIR)/csrc/u8g2_circle.o \
+ $(U8G2_DIR)/csrc/u8g2_cleardisplay.o \
+ $(U8G2_DIR)/csrc/u8g2_d_memory.o \
+ $(U8G2_DIR)/csrc/u8g2_d_setup.o \
+ $(U8G2_DIR)/csrc/u8g2_font.o \
+ $(U8G2_DIR)/csrc/u8g2_fonts.o \
+ $(U8G2_DIR)/csrc/u8g2_hvline.o \
+ $(U8G2_DIR)/csrc/u8g2_input_value.o \
+ $(U8G2_DIR)/csrc/u8g2_intersection.o \
+ $(U8G2_DIR)/csrc/u8g2_kerning.o \
+ $(U8G2_DIR)/csrc/u8g2_line.o \
+ $(U8G2_DIR)/csrc/u8g2_ll_hvline.o \
+ $(U8G2_DIR)/csrc/u8g2_message.o \
+ $(U8G2_DIR)/csrc/u8g2_polygon.o \
+ $(U8G2_DIR)/csrc/u8g2_selection_list.o \
+ $(U8G2_DIR)/csrc/u8g2_setup.o \
+ $(U8G2_DIR)/csrc/u8log.o \
+ $(U8G2_DIR)/csrc/u8log_u8g2.o \
+ $(U8G2_DIR)/csrc/u8log_u8x8.o \
+ $(U8G2_DIR)/csrc/u8x8_8x8.o \
+ $(U8G2_DIR)/csrc/u8x8_byte.o \
+ $(U8G2_DIR)/csrc/u8x8_cad.o \
+ $(U8G2_DIR)/csrc/u8x8_capture.o \
+ $(U8G2_DIR)/csrc/u8x8_d_a2printer.o \
+ $(U8G2_DIR)/csrc/u8x8_d_gu800.o \
+ $(U8G2_DIR)/csrc/u8x8_d_hd44102.o \
+ $(U8G2_DIR)/csrc/u8x8_d_il3820_296x128.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ist3020.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ist7920.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ks0108.o \
+ $(U8G2_DIR)/csrc/u8x8_d_lc7981.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ld7032_60x32.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ls013b7dh03.o \
+ $(U8G2_DIR)/csrc/u8x8_d_max7219.o \
+ $(U8G2_DIR)/csrc/u8x8_d_pcd8544_84x48.o \
+ $(U8G2_DIR)/csrc/u8x8_d_pcf8812.o \
+ $(U8G2_DIR)/csrc/u8x8_d_pcf8814_hx1230.o \
+ $(U8G2_DIR)/csrc/u8x8_d_s1d15721.o \
+ $(U8G2_DIR)/csrc/u8x8_d_s1d15e06.o \
+ $(U8G2_DIR)/csrc/u8x8_d_sbn1661.o \
+ $(U8G2_DIR)/csrc/u8x8_d_sed1330.o \
+ $(U8G2_DIR)/csrc/u8x8_d_sh1106_64x32.o \
+ $(U8G2_DIR)/csrc/u8x8_d_sh1106_72x40.o \
+ $(U8G2_DIR)/csrc/u8x8_d_sh1107.o \
+ $(U8G2_DIR)/csrc/u8x8_d_sh1108.o \
+ $(U8G2_DIR)/csrc/u8x8_d_sh1122.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1305.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_128x32.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_128x64_noname.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_2040x16.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_48x64.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_64x32.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_64x48.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_72x40.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_96x16.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1306_96x40.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1309.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1316.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1317.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1318.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1320.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1322.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1325.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1326.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1327.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1329.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1606_172x72.o \
+ $(U8G2_DIR)/csrc/u8x8_d_ssd1607_200x200.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7511.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st75160.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st75256.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7528.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st75320.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7565.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7567.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7571.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7586s_erc240160.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7586s_s028hn118a.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7586s_ymc240160.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7588.o \
+ $(U8G2_DIR)/csrc/u8x8_d_st7920.o \
+ $(U8G2_DIR)/csrc/u8x8_d_stdio.o \
+ $(U8G2_DIR)/csrc/u8x8_d_t6963.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1601.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1604.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1608.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1609.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1610.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1611.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1617.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1638.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1701_dogs102.o \
+ $(U8G2_DIR)/csrc/u8x8_d_uc1701_mini12864.o \
+ $(U8G2_DIR)/csrc/u8x8_debounce.o \
+ $(U8G2_DIR)/csrc/u8x8_display.o \
+ $(U8G2_DIR)/csrc/u8x8_fonts.o \
+ $(U8G2_DIR)/csrc/u8x8_gpio.o \
+ $(U8G2_DIR)/csrc/u8x8_input_value.o \
+ $(U8G2_DIR)/csrc/u8x8_message.o \
+ $(U8G2_DIR)/csrc/u8x8_selection_list.o \
+ $(U8G2_DIR)/csrc/u8x8_setup.o \
+ $(U8G2_DIR)/csrc/u8x8_string.o \
+ $(U8G2_DIR)/csrc/u8x8_u16toa.o \
+ $(U8G2_DIR)/csrc/u8x8_u8toa.o
+
OBJS += \
$(SYNTH_DEXED_DIR)/PluginFx.o \
$(SYNTH_DEXED_DIR)/dexed.o \
@@ -27,19 +140,22 @@ OBJS += \
$(CMSIS_DSP_SOURCE_DIR)/FastMathFunctions/FastMathFunctions.o \
$(CMSIS_DSP_SOURCE_DIR)/FilteringFunctions/FilteringFunctions.o \
$(CMSIS_DSP_SOURCE_DIR)/CommonTables/CommonTables.o \
- $(CMSIS_DSP_COMPUTELIB_SRC_DIR)/arm_cl_tables.o
+ $(CMSIS_DSP_COMPUTELIB_SRC_DIR)/arm_cl_tables.o \
+ $(U8G2_OBJS)
INCLUDE += -I $(SYNTH_DEXED_DIR)
INCLUDE += -I $(CMSIS_CORE_INCLUDE_DIR)
INCLUDE += -I $(CMSIS_DSP_INCLUDE_DIR)
INCLUDE += -I $(CMSIS_DSP_PRIVATE_INCLUDE_DIR)
INCLUDE += -I $(CMSIS_DSP_COMPUTELIB_INCLUDE_DIR)
+INCLUDE += -I $(U8G2_DIR)/csrc
+INCLUDE += -I $(U8G2_DIR)/cppsrc
-DEFINE += -DUSE_FX
+DEFINE += -DUSE_FX -DU8X8_USE_PINS
ifeq ($(strip $(AARCH)),64)
DEFINE += -DARM_MATH_NEON
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]
+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] $(U8G2_DIR)/cppsrc/*.[od] $(U8G2_DIR)/csrc/*.[od]
diff --git a/src/mididevice.cpp b/src/mididevice.cpp
index 4e15cf1..23f53f9 100644
--- a/src/mididevice.cpp
+++ b/src/mididevice.cpp
@@ -20,42 +20,27 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
-
-#include
#include "mididevice.h"
#include "minidexed.h"
#include "config.h"
#include
#include
-LOGMODULE ("mididevice");
-
#define MIDI_NOTE_OFF 0b1000
#define MIDI_NOTE_ON 0b1001
#define MIDI_AFTERTOUCH 0b1010 // TODO
#define MIDI_CONTROL_CHANGE 0b1011
#define MIDI_CC_BANK_SELECT_MSB 0 // TODO
- #define MIDI_CC_MODULATION 1
- #define MIDI_CC_VOLUME 7
- #define MIDI_CC_PAN_POSITION 10
+ #define MIDI_CC_MODULATION 1
+ #define MIDI_CC_VOLUME 7
#define MIDI_CC_BANK_SELECT_LSB 32
#define MIDI_CC_BANK_SUSTAIN 64
- #define MIDI_CC_RESONANCE 71
- #define MIDI_CC_FREQUENCY_CUTOFF 74
- #define MIDI_CC_REVERB_LEVEL 91
- #define MIDI_CC_DETUNE_LEVEL 94
- #define MIDI_CC_ALL_SOUND_OFF 120
- #define MIDI_CC_ALL_NOTES_OFF 123
#define MIDI_PROGRAM_CHANGE 0b1100
#define MIDI_PITCH_BEND 0b1110
-#define MIDI_SYSTEM_EXCLUSIVE_BEGIN 0xF0
-#define MIDI_SYSTEM_EXCLUSIVE_END 0xF7
#define MIDI_TIMING_CLOCK 0xF8
#define MIDI_ACTIVE_SENSING 0xFE
-CMIDIDevice::TDeviceMap CMIDIDevice::s_DeviceMap;
-
CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig)
: m_pSynthesizer (pSynthesizer),
m_pConfig (pConfig)
@@ -85,6 +70,8 @@ u8 CMIDIDevice::GetChannel (unsigned nTG) const
void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable)
{
+ assert (m_pSynthesizer != 0);
+
// The packet contents are just normal MIDI data - see
// https://www.midi.org/specifications/item/table-1-summary-of-midi-message
@@ -110,366 +97,113 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
(unsigned) pMessage[0], (unsigned) pMessage[1],
(unsigned) pMessage[2]);
break;
- default:
- switch(pMessage[0])
- {
- case MIDI_SYSTEM_EXCLUSIVE_BEGIN:
- printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength));
- for (uint16_t i = 0; i < nLength; i++)
- {
- if((i % 16) == 0)
- printf("\n%04d:",i);
- printf(" 0x%02x",pMessage[i]);
- }
- printf("\n");
- break;
- default:
- printf("MIDI%u: Unhandled MIDI event type %0x02x\n",nCable,pMessage[0]);
- }
- break;
- }
- }
-
- // Only for debugging:
-/*
- if(pMessage[0]==MIDI_SYSTEM_EXCLUSIVE_BEGIN)
- {
- printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength));
- for (uint16_t i = 0; i < nLength; i++)
- {
- if((i % 16) == 0)
- printf("\n%04d:",i);
- printf(" 0x%02x",pMessage[i]);
- }
- printf("\n");
- }
-*/
-
- // Handle MIDI Thru
- if (m_DeviceName.compare (m_pConfig->GetMIDIThruIn ()) == 0)
- {
- TDeviceMap::const_iterator Iterator;
-
- Iterator = s_DeviceMap.find (m_pConfig->GetMIDIThruOut ());
- if (Iterator != s_DeviceMap.end ())
- {
- Iterator->second->Send (pMessage, nLength, nCable);
}
}
if (nLength < 2)
{
- LOGERR("MIDI message is shorter than 2 bytes!");
return;
}
- m_MIDISpinLock.Acquire ();
-
u8 ucStatus = pMessage[0];
u8 ucChannel = ucStatus & 0x0F;
u8 ucType = ucStatus >> 4;
- // GLOBAL MIDI SYSEX
- if (pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN && pMessage[3] == 0x04 && pMessage[4] == 0x01 && pMessage[nLength-1] == MIDI_SYSTEM_EXCLUSIVE_END) // MASTER VOLUME
- {
- float32_t nMasterVolume=((pMessage[5] & 0x7c) & ((pMessage[6] & 0x7c) <<7))/(1<<14);
- LOGNOTE("Master volume: %f",nMasterVolume);
- m_pSynthesizer->setMasterVolume(nMasterVolume);
- }
- else
+ for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
- for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
+ if ( m_ChannelMap[nTG] == ucChannel
+ || m_ChannelMap[nTG] == OmniMode)
{
- if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN)
+ switch (ucType)
{
- // MIDI SYSEX per MIDI channel
- uint8_t ucSysExChannel = (pMessage[2] & 0x07);
- if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode)
+ case MIDI_NOTE_ON:
+ if (nLength < 3)
{
- LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG);
- HandleSystemExclusive(pMessage, nLength, nCable, nTG);
+ break;
}
- }
- else
- {
- if ( m_ChannelMap[nTG] == ucChannel
- || m_ChannelMap[nTG] == OmniMode)
+
+ if (pMessage[2] > 0)
{
- switch (ucType)
+ if (pMessage[2] <= 127)
{
- case MIDI_NOTE_ON:
- if (nLength < 3)
- {
- break;
- }
-
- if (pMessage[2] > 0)
- {
- if (pMessage[2] <= 127)
- {
- m_pSynthesizer->keydown (pMessage[1],
- pMessage[2], nTG);
- }
- }
- else
- {
- m_pSynthesizer->keyup (pMessage[1], nTG);
- }
- break;
-
- case MIDI_NOTE_OFF:
- if (nLength < 3)
- {
- break;
- }
-
- m_pSynthesizer->keyup (pMessage[1], nTG);
- break;
-
- case MIDI_CONTROL_CHANGE:
- if (nLength < 3)
- {
- break;
- }
-
- switch (pMessage[1])
- {
- case MIDI_CC_MODULATION:
- m_pSynthesizer->setModWheel (pMessage[2], nTG);
- m_pSynthesizer->ControllersRefresh (nTG);
- break;
-
- case MIDI_CC_VOLUME:
- m_pSynthesizer->SetVolume (pMessage[2], nTG);
- break;
-
- case MIDI_CC_PAN_POSITION:
- m_pSynthesizer->SetPan (pMessage[2], nTG);
- break;
-
- case MIDI_CC_BANK_SELECT_LSB:
- m_pSynthesizer->BankSelectLSB (pMessage[2], nTG);
- break;
-
- case MIDI_CC_BANK_SUSTAIN:
- m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
- break;
-
- case MIDI_CC_RESONANCE:
- m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG);
- break;
-
- case MIDI_CC_FREQUENCY_CUTOFF:
- m_pSynthesizer->SetCutoff (maplong (pMessage[2], 0, 127, 0, 99), nTG);
- break;
-
- case MIDI_CC_REVERB_LEVEL:
- m_pSynthesizer->SetReverbSend (maplong (pMessage[2], 0, 127, 0, 99), nTG);
- break;
-
- case MIDI_CC_DETUNE_LEVEL:
- if (pMessage[2] == 0)
- {
- // "0 to 127, with 0 being no celeste (detune) effect applied at all."
- m_pSynthesizer->SetMasterTune (0, nTG);
- }
- else
- {
- m_pSynthesizer->SetMasterTune (maplong (pMessage[2], 1, 127, -99, 99), nTG);
- }
- break;
-
- case MIDI_CC_ALL_SOUND_OFF:
- m_pSynthesizer->panic (pMessage[2], nTG);
- break;
-
- case MIDI_CC_ALL_NOTES_OFF:
- m_pSynthesizer->notesOff (pMessage[2], nTG);
- break;
- }
- break;
-
- case MIDI_PROGRAM_CHANGE:
- // do program change only if enabled in config
- if( m_pConfig->GetMIDIRXProgramChange() )
- m_pSynthesizer->ProgramChange (pMessage[1], nTG);
- break;
-
- case MIDI_PITCH_BEND: {
- if (nLength < 3)
- {
- break;
- }
-
- s16 nValue = pMessage[1];
- nValue |= (s16) pMessage[2] << 7;
- nValue -= 0x2000;
-
- m_pSynthesizer->setPitchbend (nValue, nTG);
- } break;
-
- default:
- break;
+ m_pSynthesizer->keydown (pMessage[1],
+ pMessage[2], nTG);
}
}
- }
- }
- }
- m_MIDISpinLock.Release ();
-}
+ else
+ {
+ m_pSynthesizer->keyup (pMessage[1], nTG);
+ }
+ break;
-void CMIDIDevice::AddDevice (const char *pDeviceName)
-{
- assert (pDeviceName);
+ case MIDI_NOTE_OFF:
+ if (nLength < 3)
+ {
+ break;
+ }
- assert (m_DeviceName.empty ());
- m_DeviceName = pDeviceName;
- assert (!m_DeviceName.empty ());
+ m_pSynthesizer->keyup (pMessage[1], nTG);
+ break;
- s_DeviceMap.insert (std::pair (pDeviceName, this));
-}
+ case MIDI_CONTROL_CHANGE:
+ if (nLength < 3)
+ {
+ break;
+ }
-void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG)
-{
- int16_t sysex_return;
+ switch (pMessage[1])
+ {
+ case MIDI_CC_MODULATION:
+ m_pSynthesizer->setModWheel (pMessage[2], nTG);
+ m_pSynthesizer->ControllersRefresh (nTG);
+ break;
- sysex_return = m_pSynthesizer->checkSystemExclusive(pMessage, nLength, nTG);
- LOGDBG("SYSEX handler return value: %d", sysex_return);
+ case MIDI_CC_VOLUME:
+ m_pSynthesizer->SetVolume (pMessage[2], nTG);
+ break;
- switch (sysex_return)
- {
- case -1:
- LOGERR("SysEx end status byte not detected.");
- break;
- case -2:
- LOGERR("SysEx vendor not Yamaha.");
- break;
- case -3:
- LOGERR("Unknown SysEx parameter change.");
- break;
- case -4:
- LOGERR("Unknown SysEx voice or function.");
- break;
- case -5:
- LOGERR("Not a SysEx voice bulk upload.");
- break;
- case -6:
- LOGERR("Wrong length for SysEx voice bulk upload (not 155).");
- break;
- case -7:
- LOGERR("Checksum error for one voice.");
- break;
- case -8:
- LOGERR("Not a SysEx bank bulk upload.");
- break;
- case -9:
- LOGERR("Wrong length for SysEx bank bulk upload (not 4096).");
- case -10:
- LOGERR("Checksum error for bank.");
- break;
- case -11:
- LOGERR("Unknown SysEx message.");
- break;
- case 64:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setMonoMode(pMessage[5],nTG);
- break;
- case 65:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setPitchbendRange(pMessage[5],nTG);
- break;
- case 66:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setPitchbendStep(pMessage[5],nTG);
- break;
- case 67:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setPortamentoMode(pMessage[5],nTG);
- break;
- case 68:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setPortamentoGlissando(pMessage[5],nTG);
- break;
- case 69:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setPortamentoTime(pMessage[5],nTG);
- break;
- case 70:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setModWheelRange(pMessage[5],nTG);
- break;
- case 71:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setModWheelTarget(pMessage[5],nTG);
- break;
- case 72:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setFootControllerRange(pMessage[5],nTG);
- break;
- case 73:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setFootControllerTarget(pMessage[5],nTG);
- break;
- case 74:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setBreathControllerRange(pMessage[5],nTG);
- break;
- case 75:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setBreathControllerTarget(pMessage[5],nTG);
- break;
- case 76:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setAftertouchRange(pMessage[5],nTG);
- break;
- case 77:
- LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
- m_pSynthesizer->setAftertouchTarget(pMessage[5],nTG);
- break;
- case 100:
- // load sysex-data into voice memory
- LOGDBG("One Voice bulk upload");
- m_pSynthesizer->loadVoiceParameters(pMessage,nTG);
- break;
- case 200:
- LOGDBG("Bank bulk upload.");
- //TODO: add code for storing a bank bulk upload
- LOGNOTE("Currently code for storing a bulk bank upload is missing!");
- break;
- default:
- if(sysex_return >= 300 && sysex_return < 500)
- {
- LOGDBG("SysEx voice parameter change: Parameter %d value: %d",pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5]);
- m_pSynthesizer->setVoiceDataElement(pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5],nTG);
- switch(pMessage[4] + ((pMessage[3] & 0x03) * 128))
- {
- case 134:
- m_pSynthesizer->notesOff(0,nTG);
- break;
- }
- }
- else if(sysex_return >= 500 && sysex_return < 600)
- {
- LOGDBG("SysEx send voice %u request",sysex_return-500);
- SendSystemExclusiveVoice(sysex_return-500, nCable, nTG);
- }
- break;
- }
-}
+ case MIDI_CC_BANK_SELECT_MSB:
+ {
+ int bank = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG);
+ bank = (pMessage[2] << 7) + (bank & 0b01111111);
+ m_pSynthesizer->BankSelect (bank, nTG);
+ }
+ break;
-void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable, uint8_t nTG)
-{
- uint8_t voicedump[163];
+ case MIDI_CC_BANK_SELECT_LSB:
+ {
+ int bank = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG);
+ bank = (bank & 0b011111110000000) + pMessage[2];
+ m_pSynthesizer->BankSelect (bank, nTG);
+ }
+ break;
+
+ case MIDI_CC_BANK_SUSTAIN:
+ m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
+ break;
+ }
+ break;
+
+ case MIDI_PROGRAM_CHANGE:
+ m_pSynthesizer->ProgramChange (pMessage[1], nTG);
+ break;
- // Get voice sysex dump from TG
- m_pSynthesizer->getSysExVoiceDump(voicedump, nTG);
+ case MIDI_PITCH_BEND: {
+ if (nLength < 3)
+ {
+ break;
+ }
+
+ s16 nValue = pMessage[1];
+ nValue |= (s16) pMessage[2] << 7;
+ nValue -= 0x2000;
- TDeviceMap::const_iterator Iterator;
+ m_pSynthesizer->setPitchbend (nValue, nTG);
+ } break;
- // send voice dump to all MIDI interfaces
- for(Iterator = s_DeviceMap.begin(); Iterator != s_DeviceMap.end(); ++Iterator)
- {
- Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t));
- LOGDBG("Send SYSEX voice dump %u to \"%s\"",nVoice,Iterator->first.c_str());
- }
-}
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/src/minidexed.cpp b/src/minidexed.cpp
index c09eb42..2211bc4 100644
--- a/src/minidexed.cpp
+++ b/src/minidexed.cpp
@@ -23,7 +23,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -37,7 +36,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
CMultiCoreSupport (CMemorySystem::Get ()),
#endif
m_pConfig (pConfig),
- m_UI (this, pGPIOManager, pI2CMaster, pConfig),
+ m_UI (this, pGPIOManager, pConfig),
m_PerformanceConfig (pFileSystem),
m_PCKeyboard (this, pConfig),
m_SerialMIDI (this, pInterrupt, pConfig),
@@ -49,10 +48,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
#endif
m_GetChunkTimer ("GetChunk",
1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()),
- m_bProfileEnabled (m_pConfig->GetProfileEnabled ()),
- m_bSavePerformance (false),
- m_bSavePerformanceNewFile (false),
- m_bSetNewPerformance (false)
+ m_bProfileEnabled (m_pConfig->GetProfileEnabled ())
{
assert (m_pConfig);
@@ -66,18 +62,12 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
m_nCutoff[i] = 99;
m_nResonance[i] = 0;
m_nMIDIChannel[i] = CMIDIDevice::Disabled;
- m_nPitchBendRange[i] = 2;
- m_nPitchBendStep[i] = 0;
- m_nPortamentoMode[i] = 0;
- m_nPortamentoGlissando[i] = 0;
- m_nPortamentoTime[i] = 0;
m_nNoteLimitLow[i] = 0;
m_nNoteLimitHigh[i] = 127;
m_nNoteShift[i] = 0;
m_nReverbSend[i] = 0;
- m_uchOPMask[i] = 0b111111; // All operators on
m_pTG[i] = new CDexedAdapter (CConfig::MaxNotes, pConfig->GetSampleRate ());
assert (m_pTG[i]);
@@ -127,8 +117,6 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
}
#endif
- setMasterVolume(1.0);
-
// BEGIN setup tg_mixer
tg_mixer = new AudioStereoMixer(pConfig->GetChunkSize()/2);
// END setup tgmixer
@@ -158,6 +146,7 @@ bool CMiniDexed::Initialize (void)
return false;
}
+ m_UI.ImmediateLCDWrite("Loading all banks & presets.");
m_SysExFileLoader.Load ();
if (m_SerialMIDI.Initialize ())
@@ -176,7 +165,7 @@ bool CMiniDexed::Initialize (void)
m_pTG[i]->setTranspose (24);
- m_pTG[i]->setPBController (2, 0);
+ m_pTG[i]->setPBController (12, 1);
m_pTG[i]->setMWController (99, 7, 0);
tg_mixer->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f));
@@ -187,19 +176,39 @@ bool CMiniDexed::Initialize (void)
if (m_PerformanceConfig.Load ())
{
- LoadPerformanceParameters();
+ for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; 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);
+
+ m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG);
+ m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG);
+ m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG);
+
+ SetReverbSend (m_PerformanceConfig.GetReverbSend (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 ());
}
else
{
SetMIDIChannel (CMIDIDevice::OmniMode, 0);
}
-
- // load performances file list, and attempt to create the performance folder
- if (!m_PerformanceConfig.ListPerformances())
- {
- LOGERR ("Cannot create internal Performance folder, new performances can't be created");
- }
-
+
// setup and start the sound device
if (!m_pSoundDevice->AllocateQueueFrames (m_pConfig->GetChunkSize ()))
{
@@ -250,25 +259,6 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated)
m_UI.Process ();
- if (m_bSavePerformance)
- {
- DoSavePerformance ();
-
- m_bSavePerformance = false;
- }
-
- if (m_bSavePerformanceNewFile)
- {
- DoSavePerformanceNewFile ();
- m_bSavePerformanceNewFile = false;
- }
-
- if (m_bSetNewPerformance)
- {
- DoSetNewPerformance ();
- m_bSetNewPerformance = false;
- }
-
if (m_bProfileEnabled)
{
m_GetChunkTimer.Dump ();
@@ -340,12 +330,12 @@ CSysExFileLoader *CMiniDexed::GetSysExFileLoader (void)
return &m_SysExFileLoader;
}
-void CMiniDexed::BankSelectLSB (unsigned nBankLSB, unsigned nTG)
+void CMiniDexed::BankSelect (unsigned nBank, unsigned nTG)
{
- nBankLSB=constrain((int)nBankLSB,0,127);
+ nBank=constrain((int)nBank,0,1 << 14 - 1);
assert (nTG < CConfig::ToneGenerators);
- m_nVoiceBankID[nTG] = nBankLSB;
+ m_nVoiceBankID[nTG] = nBank;
m_UI.ParameterChanged ();
}
@@ -362,7 +352,6 @@ void CMiniDexed::ProgramChange (unsigned nProgram, unsigned nTG)
assert (m_pTG[nTG]);
m_pTG[nTG]->loadVoiceParameters (Buffer);
- m_SerialMIDI.SendSystemExclusiveVoice(nProgram,0,nTG);
m_UI.ParameterChanged ();
}
@@ -444,8 +433,6 @@ void CMiniDexed::SetResonance (int nResonance, unsigned nTG)
m_UI.ParameterChanged ();
}
-
-
void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG)
{
assert (nTG < CConfig::ToneGenerators);
@@ -534,24 +521,6 @@ void CMiniDexed::setSustain(bool sustain, unsigned nTG)
m_pTG[nTG]->setSustain (sustain);
}
-void CMiniDexed::panic(uint8_t value, unsigned nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
- if (value == 0) {
- m_pTG[nTG]->panic ();
- }
-}
-
-void CMiniDexed::notesOff(uint8_t value, unsigned nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
- if (value == 0) {
- m_pTG[nTG]->notesOff ();
- }
-}
-
void CMiniDexed::setModWheel (uint8_t value, unsigned nTG)
{
assert (nTG < CConfig::ToneGenerators);
@@ -657,18 +626,13 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT
switch (Parameter)
{
- case TGParameterVoiceBank: BankSelectLSB (nValue, nTG); break;
+ case TGParameterVoiceBank: BankSelect (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 TGParameterMIDIChannel:
assert (0 <= nValue && nValue <= 255);
@@ -698,11 +662,6 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG)
case TGParameterResonance: return m_nResonance[nTG];
case TGParameterMIDIChannel: return m_nMIDIChannel[nTG];
case TGParameterReverbSend: return m_nReverbSend[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];
default:
assert (0);
@@ -718,22 +677,6 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne
if (nOP < 6)
{
- if (uchOffset == DEXED_OP_ENABLE)
- {
- if (uchValue)
- {
- m_uchOPMask[nTG] |= 1 << nOP;
- }
- else
- {
- m_uchOPMask[nTG] &= ~(1 << nOP);
- }
-
- m_pTG[nTG]->setOPAll (m_uchOPMask[nTG]);
-
- return;
- }
-
nOP = 5 - nOP; // OPs are in reverse order
}
@@ -751,11 +694,6 @@ uint8_t CMiniDexed::GetVoiceParameter (uint8_t uchOffset, unsigned nOP, unsigned
if (nOP < 6)
{
- if (uchOffset == DEXED_OP_ENABLE)
- {
- return !!(m_uchOPMask[nTG] & (1 << nOP));
- }
-
nOP = 5 - nOP; // OPs are in reverse order
}
@@ -867,70 +805,56 @@ void CMiniDexed::ProcessSound (void)
}
// BEGIN TG mixing
- float32_t tmp_float[nFrames*2];
- int16_t tmp_int[nFrames*2];
+ for (uint8_t i = 0; i < CConfig::ToneGenerators; i++)
+ {
+ tg_mixer->doAddMix(i,m_OutputLevel[i]);
+ reverb_send_mixer->doAddMix(i,m_OutputLevel[i]);
+ }
+ // END TG mixing
+
+ // BEGIN create SampleBuffer for holding audio data
+ float32_t SampleBuffer[2][nFrames];
+ // END create SampleBuffer for holding audio data
- if(nMasterVolume > 0.0)
+ // get the mix of all TGs
+ tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]);
+
+ // BEGIN adding reverb
+ if (m_nParameter[ParameterReverbEnable])
{
- for (uint8_t i = 0; i < CConfig::ToneGenerators; i++)
- {
- tg_mixer->doAddMix(i,m_OutputLevel[i]);
- reverb_send_mixer->doAddMix(i,m_OutputLevel[i]);
- }
- // END TG mixing
-
- // BEGIN create SampleBuffer for holding audio data
- float32_t SampleBuffer[2][nFrames];
- // END create SampleBuffer for holding audio data
+ float32_t ReverbBuffer[2][nFrames];
+ float32_t ReverbSendBuffer[2][nFrames];
- // get the mix of all TGs
- tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]);
+ arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames);
+ arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames);
+ arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames);
+ arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames);
- // BEGIN adding reverb
- if (m_nParameter[ParameterReverbEnable])
- {
- float32_t ReverbBuffer[2][nFrames];
- float32_t ReverbSendBuffer[2][nFrames];
+ m_ReverbSpinLock.Acquire ();
- arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames);
- arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames);
- arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames);
- arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames);
-
- m_ReverbSpinLock.Acquire ();
-
- reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]);
- reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames);
-
- // 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);
-
- m_ReverbSpinLock.Release ();
- }
- // END adding reverb
-
- // Convert dual float array (left, right) to single int16 array (left/right)
- for(uint16_t i=0; i0.0 && nMasterVolume <1.0)
- {
- tmp_float[i*2]=SampleBuffer[indexL][i] * nMasterVolume;
- tmp_float[(i*2)+1]=SampleBuffer[indexR][i] * nMasterVolume;
- }
- else if(nMasterVolume == 1.0)
- {
- tmp_float[i*2]=SampleBuffer[indexL][i];
- tmp_float[(i*2)+1]=SampleBuffer[indexR][i];
- }
- }
- arm_float_to_q15(tmp_float,tmp_int,nFrames*2);
+ reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]);
+ reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames);
+
+ // 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);
+
+ m_ReverbSpinLock.Release ();
}
- else
- arm_fill_q15(0, tmp_int, nFrames * 2);
+ // END adding reverb
+
+ // Convert dual float array (left, right) to single int16 array (left/right)
+ float32_t tmp_float[nFrames*2];
+ int16_t tmp_int[nFrames*2];
+ for(uint16_t i=0; iWrite (tmp_int, sizeof(tmp_int)) != (int) sizeof(tmp_int))
{
@@ -947,13 +871,6 @@ void CMiniDexed::ProcessSound (void)
#endif
bool CMiniDexed::SavePerformance (void)
-{
- m_bSavePerformance = true;
-
- return true;
-}
-
-bool CMiniDexed::DoSavePerformance (void)
{
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
@@ -965,18 +882,11 @@ bool CMiniDexed::DoSavePerformance (void)
m_PerformanceConfig.SetDetune (m_nMasterTune[nTG], nTG);
m_PerformanceConfig.SetCutoff (m_nCutoff[nTG], nTG);
m_PerformanceConfig.SetResonance (m_nResonance[nTG], nTG);
- m_PerformanceConfig.SetPitchBendRange (m_nPitchBendRange[nTG], nTG);
- m_PerformanceConfig.SetPitchBendStep (m_nPitchBendStep[nTG], nTG);
- m_PerformanceConfig.SetPortamentoMode (m_nPortamentoMode[nTG], nTG);
- m_PerformanceConfig.SetPortamentoGlissando (m_nPortamentoGlissando[nTG], nTG);
- m_PerformanceConfig.SetPortamentoTime (m_nPortamentoTime[nTG], nTG);
m_PerformanceConfig.SetNoteLimitLow (m_nNoteLimitLow[nTG], nTG);
m_PerformanceConfig.SetNoteLimitHigh (m_nNoteLimitHigh[nTG], nTG);
m_PerformanceConfig.SetNoteShift (m_nNoteShift[nTG], nTG);
- m_pTG[nTG]->getVoiceData(m_nRawVoiceData);
- m_PerformanceConfig.SetVoiceDataToTxt (m_nRawVoiceData, nTG);
-
+
m_PerformanceConfig.SetReverbSend (m_nReverbSend[nTG], nTG);
}
@@ -991,364 +901,3 @@ bool CMiniDexed::DoSavePerformance (void)
return m_PerformanceConfig.Save ();
}
-
-void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setMonoMode(constrain(mono, 0, 1));
- m_pTG[nTG]->doRefreshVoice();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG)
-{
- range = constrain (range, 0, 12);
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
- m_nPitchBendRange[nTG] = range;
-
- m_pTG[nTG]->setPitchbendRange(range);
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setPitchbendStep(uint8_t step, uint8_t nTG)
-{
- step= constrain (step, 0, 12);
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
- m_nPitchBendStep[nTG] = step;
-
- m_pTG[nTG]->setPitchbendStep(step);
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setPortamentoMode(uint8_t mode, uint8_t nTG)
-{
- mode= constrain (mode, 0, 1);
-
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
- m_nPortamentoMode[nTG] = mode;
-
- m_pTG[nTG]->setPortamentoMode(mode);
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setPortamentoGlissando(uint8_t glissando, uint8_t nTG)
-{
- glissando = constrain (glissando, 0, 1);
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
- m_nPortamentoGlissando[nTG] = glissando;
-
- m_pTG[nTG]->setPortamentoGlissando(glissando);
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setPortamentoTime(uint8_t time, uint8_t nTG)
-{
- time = constrain (time, 0, 99);
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
- m_nPortamentoTime[nTG] = time;
-
- m_pTG[nTG]->setPortamentoTime(time);
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setModWheelRange(uint8_t range, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setModWheelRange(constrain(range, 0, 99));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setModWheelTarget(uint8_t target, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setModWheelTarget(constrain(target, 0, 7));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setFootControllerRange(uint8_t range, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setFootControllerRange(constrain(range, 0, 99));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setFootControllerTarget(uint8_t target, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setFootControllerTarget(constrain(target, 0, 7));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setBreathControllerRange(uint8_t range, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setBreathControllerRange(constrain(range, 0, 99));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setBreathControllerTarget(uint8_t target, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setBreathControllerTarget(constrain(target, 0, 7));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setAftertouchRange(uint8_t range, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setAftertouchRange(constrain(range, 0, 99));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setAftertouchTarget(uint8_t target, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setAftertouchTarget(constrain(target, 0, 7));
- m_pTG[nTG]->ControllersRefresh();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::loadVoiceParameters(const uint8_t* data, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- uint8_t voice[161];
-
- memcpy(voice, data, sizeof(uint8_t)*161);
-
- // fix voice name
- for (uint8_t i = 0; i < 10; i++)
- {
- if (voice[151 + i] > 126) // filter characters
- voice[151 + i] = 32;
- }
-
- m_pTG[nTG]->loadVoiceParameters(&voice[6]);
- m_pTG[nTG]->doRefreshVoice();
- m_UI.ParameterChanged ();
-}
-
-void CMiniDexed::setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->setVoiceDataElement(constrain(data, 0, 155),constrain(number, 0, 99));
- //m_pTG[nTG]->doRefreshVoice();
- m_UI.ParameterChanged ();
-}
-
-int16_t CMiniDexed::checkSystemExclusive(const uint8_t* pMessage,const uint16_t nLength, uint8_t nTG)
-{
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- return(m_pTG[nTG]->checkSystemExclusive(pMessage, nLength));
-}
-
-void CMiniDexed::getSysExVoiceDump(uint8_t* dest, uint8_t nTG)
-{
- uint8_t checksum = 0;
- uint8_t data[155];
-
- assert (nTG < CConfig::ToneGenerators);
- assert (m_pTG[nTG]);
-
- m_pTG[nTG]->getVoiceData(data);
-
- dest[0] = 0xF0; // SysEx start
- dest[1] = 0x43; // ID=Yamaha
- dest[2] = GetTGParameter(TGParameterMIDIChannel, nTG); // Sub-status and MIDI channel
- dest[3] = 0x00; // Format number (0=1 voice)
- dest[4] = 0x01; // Byte count MSB
- dest[5] = 0x1B; // Byte count LSB
- for (uint8_t n = 0; n < 155; n++)
- {
- checksum -= data[n];
- dest[6 + n] = data[n];
- }
- dest[161] = checksum & 0x7f; // Checksum
- dest[162] = 0xF7; // SysEx end
-}
-
-void CMiniDexed::setMasterVolume (float32_t vol)
-{
- if(vol < 0.0)
- vol = 0.0;
- else if(vol > 1.0)
- vol = 1.0;
-
- nMasterVolume=vol;
-}
-
-std::string CMiniDexed::GetPerformanceFileName(unsigned nID)
-{
- return m_PerformanceConfig.GetPerformanceFileName(nID);
-}
-
-std::string CMiniDexed::GetPerformanceName(unsigned nID)
-{
- return m_PerformanceConfig.GetPerformanceName(nID);
-}
-
-unsigned CMiniDexed::GetLastPerformance()
-{
- return m_PerformanceConfig.GetLastPerformance();
-}
-
-
-
-unsigned CMiniDexed::GetActualPerformanceID()
-{
- return m_PerformanceConfig.GetActualPerformanceID();
-}
-
-void CMiniDexed::SetActualPerformanceID(unsigned nID)
-{
- m_PerformanceConfig.SetActualPerformanceID(nID);
-}
-
-unsigned CMiniDexed::GetMenuSelectedPerformanceID()
-{
- return m_PerformanceConfig.GetMenuSelectedPerformanceID();
-}
-
-void CMiniDexed::SetMenuSelectedPerformanceID(unsigned nID)
-{
- m_PerformanceConfig.SetMenuSelectedPerformanceID(nID);
-}
-
-
-bool CMiniDexed::SetNewPerformance(unsigned nID)
-{
- m_bSetNewPerformance = true;
- m_nSetNewPerformanceID = nID;
-
- return true;
-}
-
-bool CMiniDexed::DoSetNewPerformance (void)
-{
- unsigned nID = m_nSetNewPerformanceID;
- m_PerformanceConfig.SetNewPerformance(nID);
-
- if (m_PerformanceConfig.Load ())
- {
- LoadPerformanceParameters();
- return true;
- }
- else
- {
- SetMIDIChannel (CMIDIDevice::OmniMode, 0);
- return false;
- }
-}
-
-bool CMiniDexed::SavePerformanceNewFile ()
-{
- m_bSavePerformanceNewFile = m_PerformanceConfig.GetInternalFolderOk();
- return m_bSavePerformanceNewFile;
-}
-
-bool CMiniDexed::DoSavePerformanceNewFile (void)
-{
- std::string nPerformanceName=""; // for future enhacements: capability to write performance name
- if (m_PerformanceConfig.CreateNewPerformanceFile(nPerformanceName))
- {
- if(SavePerformance())
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
-
-}
-
-
-void CMiniDexed::LoadPerformanceParameters(void)
-{
- for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
- {
-
- BankSelectLSB (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);
- }
-
- SetReverbSend (m_PerformanceConfig.GetReverbSend (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 ());
-}
-
diff --git a/src/minidexed.h b/src/minidexed.h
index 6945845..96740ad 100644
--- a/src/minidexed.h
+++ b/src/minidexed.h
@@ -63,7 +63,7 @@ public:
CSysExFileLoader *GetSysExFileLoader (void);
- void BankSelectLSB (unsigned nBankLSB, unsigned nTG);
+ void BankSelect (unsigned nBank, unsigned nTG);
void ProgramChange (unsigned nProgram, unsigned nTG);
void SetVolume (unsigned nVolume, unsigned nTG);
void SetPan (unsigned nPan, unsigned nTG); // 0 .. 127
@@ -76,47 +76,12 @@ public:
void keydown (int16_t pitch, uint8_t velocity, unsigned nTG);
void setSustain (bool sustain, unsigned nTG);
- void panic (uint8_t value, unsigned nTG);
- void notesOff (uint8_t value, unsigned nTG);
void setModWheel (uint8_t value, unsigned nTG);
void setPitchbend (int16_t value, unsigned nTG);
void ControllersRefresh (unsigned nTG);
void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127
- void setMonoMode(uint8_t mono, 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 setModWheelRange(uint8_t range, uint8_t nTG);
- void setModWheelTarget(uint8_t target, uint8_t nTG);
- void setFootControllerRange(uint8_t range, uint8_t nTG);
- void setFootControllerTarget(uint8_t target, uint8_t nTG);
- void setBreathControllerRange(uint8_t range, uint8_t nTG);
- void setBreathControllerTarget(uint8_t target, uint8_t nTG);
- void setAftertouchRange(uint8_t range, uint8_t nTG);
- void setAftertouchTarget(uint8_t target, uint8_t nTG);
- void loadVoiceParameters(const uint8_t* data, uint8_t nTG);
- void setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG);
- void getSysExVoiceDump(uint8_t* dest, uint8_t nTG);
-
- int16_t checkSystemExclusive(const uint8_t* pMessage, const uint16_t nLength, uint8_t nTG);
-
- std::string GetPerformanceFileName(unsigned nID);
- std::string GetPerformanceName(unsigned nID);
- unsigned GetLastPerformance();
- unsigned GetActualPerformanceID();
- void SetActualPerformanceID(unsigned nID);
- bool SetNewPerformance(unsigned nID);
- bool SavePerformanceNewFile ();
- unsigned GetMenuSelectedPerformanceID();
- void SetMenuSelectedPerformanceID(unsigned nID);
-
- bool DoSavePerformanceNewFile (void);
- bool DoSetNewPerformance (void);
-
enum TParameter
{
ParameterCompressorEnable,
@@ -144,11 +109,6 @@ public:
TGParameterResonance,
TGParameterMIDIChannel,
TGParameterReverbSend,
- TGParameterPitchBendRange,
- TGParameterPitchBendStep,
- TGParameterPortamentoMode,
- TGParameterPortamentoGlissando,
- TGParameterPortamentoTime,
TGParameterUnknown
};
@@ -163,14 +123,10 @@ public:
std::string GetVoiceName (unsigned nTG);
bool SavePerformance (void);
- bool DoSavePerformance (void);
-
- void setMasterVolume (float32_t vol);
private:
int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note
- uint8_t m_uchOPMask[CConfig::ToneGenerators];
- void LoadPerformanceParameters(void);
+
void ProcessSound (void);
#ifdef ARM_ALLOW_MULTI_CORE
@@ -199,28 +155,12 @@ private:
int m_nCutoff[CConfig::ToneGenerators];
int m_nResonance[CConfig::ToneGenerators];
unsigned m_nMIDIChannel[CConfig::ToneGenerators];
- unsigned m_nPitchBendRange[CConfig::ToneGenerators];
- unsigned m_nPitchBendStep[CConfig::ToneGenerators];
- unsigned m_nPortamentoMode[CConfig::ToneGenerators];
- unsigned m_nPortamentoGlissando[CConfig::ToneGenerators];
- unsigned m_nPortamentoTime[CConfig::ToneGenerators];
unsigned m_nNoteLimitLow[CConfig::ToneGenerators];
unsigned m_nNoteLimitHigh[CConfig::ToneGenerators];
int m_nNoteShift[CConfig::ToneGenerators];
unsigned m_nReverbSend[CConfig::ToneGenerators];
-
- uint8_t m_nRawVoiceData[156];
-
-
- bool m_bSavePerformanceNewFile;
- bool m_bSetNewPerformance;
- unsigned m_nSetNewPerformanceID;
-
- float32_t nMasterVolume;
-
-
CUserInterface m_UI;
CSysExFileLoader m_SysExFileLoader;
@@ -250,8 +190,6 @@ private:
AudioStereoMixer* reverb_send_mixer;
CSpinLock m_ReverbSpinLock;
-
- bool m_bSavePerformance;
};
#endif
diff --git a/src/screens.cpp b/src/screens.cpp
new file mode 100644
index 0000000..1ad838c
--- /dev/null
+++ b/src/screens.cpp
@@ -0,0 +1,64 @@
+#include "screens.h"
+
+CPerformanceScreen::CPerformanceScreen() :
+ CScreen(PerformanceScreen, "Performance", PerformanceScreenPageCount)
+{
+}
+
+CPerformanceScreen::~CPerformanceScreen()
+{
+}
+
+CPerformanceEditScreen::CPerformanceEditScreen() :
+ CScreen(PerformanceEditScreen, "Perf. edit", PerformanceEditScreenPageCount)
+{
+}
+
+CPerformanceEditScreen::~CPerformanceEditScreen()
+{
+}
+
+CVoiceScreen::CVoiceScreen() :
+ CScreen(VoiceScreen, "Voice", VoiceScreenPageCount)
+{
+}
+
+CVoiceScreen::~CVoiceScreen()
+{
+}
+
+CVoiceEditScreen::CVoiceEditScreen() :
+ CScreen(VoiceEditScreen, "Voice edit", VoiceEditScreenPageCount)
+{
+}
+
+CVoiceEditScreen::~CVoiceEditScreen()
+{
+}
+
+COperatorScreen::COperatorScreen() :
+ CScreen(OperatorScreen, "Op. edit", OperatorScreenPageCount)
+{
+}
+
+COperatorScreen::~COperatorScreen()
+{
+}
+
+CFxScreen::CFxScreen() :
+ CScreen(FxScreen, "FX", FxScreenPageCount)
+{
+}
+
+CFxScreen::~CFxScreen()
+{
+}
+
+CNameEditScreen::CNameEditScreen(const char* pszScreenName) :
+ CScreen(NameEditScreen, pszScreenName, NameEditScreenPageCount)
+{
+}
+
+CNameEditScreen::~CNameEditScreen()
+{
+}
diff --git a/src/screens.h b/src/screens.h
new file mode 100644
index 0000000..74cdd20
--- /dev/null
+++ b/src/screens.h
@@ -0,0 +1,97 @@
+//
+// minidexed.h
+//
+// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
+// Copyright (C) 2022 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 _screens_h
+#define _screens_h
+
+#include
+#include
+
+enum ScreenID
+{
+ PerformanceScreen = 0,
+ PerformanceEditScreen,
+ VoiceScreen,
+ VoiceEditScreen,
+ OperatorScreen,
+ FxScreen,
+ NameEditScreen
+};
+
+enum ScreenPageCount
+{
+ PerformanceScreenPageCount = 1,
+ PerformanceEditScreenPageCount = 3,
+ VoiceScreenPageCount = 1,
+ VoiceEditScreenPageCount = 3,
+ OperatorScreenPageCount = 1,
+ FxScreenPageCount = 1,
+ NameEditScreen = 1
+};
+
+class CPerformanceScreen : public CScreen
+{
+public:
+ CPerformanceScreen();
+ virtual ~CPerformanceScreen();
+};
+
+class CPerformanceEditScreen : public CScreen
+{
+public:
+ CPerformanceEditScreen();
+ virtual ~CPerformanceEditScreen();
+};
+
+class CVoiceScreen : public CScreen
+{
+public:
+ CVoiceScreen();
+ virtual ~CVoiceScreen();
+};
+
+class CVoiceEditScreen : public CScreen
+{
+public:
+ CVoiceEditScreen();
+ virtual ~CVoiceEditScreen();
+};
+
+class COperatorScreen : public CScreen
+{
+public:
+ COperatorScreen();
+ virtual ~COperatorScreen();
+};
+
+class CFxScreen : public CScreen
+{
+public:
+ CFxScreen();
+ ~CFxScreen();
+};
+
+class CNameEditScreen : public CScreen
+{
+public:
+ CNameEditScreen();
+ ~CNameEditScreen();
+};
+
+#endif
\ No newline at end of file
diff --git a/src/sysexfileloader.h b/src/sysexfileloader.h
index bf7c918..658f2b0 100644
--- a/src/sysexfileloader.h
+++ b/src/sysexfileloader.h
@@ -29,7 +29,7 @@
class CSysExFileLoader // Loader for DX7 .syx files
{
public:
- static const unsigned MaxVoiceBankID = 127; // TODO? 16383
+ static const unsigned MaxVoiceBankID = 1 << 14; // TODO? 16383
static const unsigned VoicesPerBank = 32;
static const size_t SizePackedVoice = 128;
static const size_t SizeSingleVoice = 156;
diff --git a/src/ui.cpp b/src/ui.cpp
new file mode 100644
index 0000000..f08e9b8
--- /dev/null
+++ b/src/ui.cpp
@@ -0,0 +1,614 @@
+#include "ui.h"
+
+#include
+
+LOGMODULE ("ui");
+
+/* CPaint */
+CPaint::CPaint(uint8_t sdi, uint8_t sda, uint8_t reset) : m_display(U8G2_R0, reset, sdi, sda)
+{
+}
+
+CPaint::~CPaint()
+{
+ this->m_display.clearDisplay();
+}
+
+void CPaint::Initialize()
+{
+ this->m_display.initDisplay();
+}
+
+uint32_t CPaint::GetBusClock()
+{
+ return this->m_display.getBusClock();
+}
+
+void CPaint::SetBusClock(uint32_t clock_speed)
+{
+ this->m_display.setBusClock(clock_speed);
+}
+
+void CPaint::SetI2CAddress(uint8_t adr)
+{
+ this->m_display.setI2CAddress(adr);
+}
+
+void CPaint::EnableUTF8Print()
+{
+ this->m_display.enableUTF8Print();
+}
+
+void CPaint::DisableUTF8Print()
+{
+ this->m_display.disableUTF8Print();
+}
+
+unsigned CPaint::Width()
+{
+ return this->m_display.getDisplayWidth();
+}
+
+unsigned CPaint::Height()
+{
+ return this->m_display.getDisplayHeight();
+}
+
+void CPaint::Clear()
+{
+ this->m_display.clearDisplay();
+}
+
+void CPaint::SetPowerSave(uint8_t is_enable)
+{
+ this->m_display.setPowerSave(is_enable);
+}
+
+void CPaint::SetFlipMode(uint8_t mode)
+{
+ this->m_display.setFlipMode(mode);
+}
+
+void CPaint::SetContrast(uint8_t value)
+{
+ this->m_display.setContrast(value);
+}
+
+bool CPaint::Begin()
+{
+ this->m_display.begin();
+}
+
+void CPaint::BeginSimple()
+{
+ this->m_display.beginSimple();
+}
+
+void CPaint::SetMaxClipWindow()
+{
+ this->m_display.setMaxClipWindow();
+}
+
+void CPaint::SetClipWindow(uint8_t clip_x0, uint8_t clip_y0, uint8_t clip_x1, uint8_t clip_y1)
+{
+ this->m_display.setClipWindow(clip_x0, clip_y0, clip_x1, clip_y1);
+}
+
+void CPaint::SendBuffer()
+{
+ this->m_display.sendBuffer();
+}
+void CPaint::ClearBuffer()
+{
+ this->m_display.clearBuffer();
+}
+
+void CPaint::FirstPage()
+{
+ this->m_display.firstPage();
+}
+uint8_t CPaint::NextPage()
+{
+ this->m_display.nextPage();
+}
+
+uint8_t* CPaint::GetBufferPtr()
+{
+ return this->m_display.getBufferPtr();
+}
+
+uint8_t CPaint::GetBufferTileHeight()
+{
+ return this->m_display.getBufferTileHeight();
+}
+
+uint8_t CPaint::GetBufferTileWidth()
+{
+ return this->m_display.getBufferTileWidth();
+}
+
+uint8_t CPaint::GetPageCurrTileRow()
+{
+ return this->m_display.getPageCurrTileRow();
+}
+
+void CPaint::SetPageCurrTileRow(uint8_t row)
+{
+ this->m_display.setPageCurrTileRow(row);
+}
+
+uint8_t CPaint::GetBufferCurrTileRow()
+{
+ return this->m_display.getBufferCurrTileRow();
+}
+
+void CPaint::SetBufferCurrTileRow(uint8_t row)
+{
+ this->m_display.setBufferCurrTileRow(row);
+}
+
+void CPaint::SetBufferAutoClear(uint8_t mode)
+{
+ this->m_display.setAutoPageClear(mode);
+}
+
+void CPaint::UpdateDisplayArea(uint8_t tx, uint8_t ty, uint8_t tw, uint8_t th)
+{
+ this->m_display.updateDisplayArea(tx, ty, tw, th);
+}
+
+void CPaint::UpdateDisplay()
+{
+ this->m_display.updateDisplay();
+}
+
+void CPaint::RefreshDisplay()
+{
+ this->m_display.refreshDisplay();
+}
+
+void CPaint::SetDrawColor(uint8_t color_index)
+{
+ this->m_display.setDrawColor(color_index);
+}
+
+uint8_t CPaint::GetDrawColor()
+{
+ this->m_display.getDrawColor();
+}
+
+void CPaint::DrawPixel(uint8_t x, uint8_t y)
+{
+ this->m_display.drawPixel(x, y);
+}
+
+void CPaint::DrawHLine(uint8_t x, uint8_t y, uint8_t w)
+{
+ this->m_display.drawHLine(x, y, w);
+}
+
+void CPaint::DrawVLine(uint8_t x, uint8_t y, uint8_t h)
+{
+ this->m_display.drawVLine(x, y, h);
+}
+
+void CPaint::DrawHVLine(uint8_t x, uint8_t y, uint8_t len, uint8_t dir)
+{
+ this->m_display.drawHVLine(x, y, len, dir);
+}
+
+void CPaint::DrawFrame(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
+{
+ this->m_display.drawFrame(x, y, w, h);
+}
+
+void CPaint::DrawRFrame(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t r)
+{
+ this->m_display.drawRFrame(x, y, w, h, r);
+}
+
+void CPaint::DrawBox(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
+{
+ this->m_display.drawBox(x, y, w, h);
+}
+
+void CPaint::DrawRBox(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t r)
+{
+ this->m_display.drawRBox(x, y, w, h, r);
+}
+
+void CPaint::DrawButtonUTF8(uint8_t x, uint8_t y, uint8_t flags, uint8_t width, uint8_t padding_h, uint8_t padding_v, const char* text)
+{
+ this->m_display.drawButtonUTF8(x, y, flags, width, padding_h, padding_v, text);
+}
+
+void CPaint::DrawCircle(uint8_t x0, uint8_t y0, uint8_t rad, uint8_t opt)
+{
+ this->m_display.drawCircle(x0, y0, rad, opt);
+}
+
+void CPaint::DrawDisc(uint8_t x0, uint8_t y0, uint8_t rad, uint8_t opt)
+{
+ this->m_display.drawDisc(x0, y0, rad, opt);
+}
+
+void CPaint::DrawEllipse(uint8_t x0, uint8_t y0, uint8_t rx, uint8_t ry, uint8_t opt)
+{
+ this->m_display.drawEllipse(x0, y0, rx, ry, opt);
+}
+
+void CPaint::DrawFilledEllipse(uint8_t x0, uint8_t y0, uint8_t rx, uint8_t ry, uint8_t opt)
+{
+ this->m_display.drawFilledEllipse(x0, y0, rx, ry, opt);
+}
+
+void CPaint::DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
+{
+ this->m_display.drawLine(x1, y1, x2, y2);
+}
+
+void CPaint::SetBitmapMode(uint8_t is_transparent)
+{
+ this->m_display.setBitmapMode(is_transparent);
+}
+
+void CPaint::DrawBitmap(uint8_t x, uint8_t y, uint8_t cnt, uint8_t h, const uint8_t* bitmap)
+{
+ this->m_display.drawBitmap(x, y, cnt, h, bitmap);
+}
+
+void CPaint::DrawXBM(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t* bitmap)
+{
+ this->m_display.drawXBM(x, y, w, h, bitmap);
+}
+
+void CPaint::DrawXBMP(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t* bitmap)
+{
+ this->m_display.drawXBMP(x, y, w, h, bitmap);
+}
+
+void CPaint::DrawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2)
+{
+ this->m_display.drawTriangle(x0, y0, x1, y1, x2, y2);
+}
+
+void CPaint::SetFont(const uint8_t* font)
+{
+ this->m_display.setFont(font);
+}
+
+void CPaint::SetFontMode(uint8_t is_transparent)
+{
+ this->m_display.setFontMode(is_transparent);
+}
+
+void CPaint::SetFontDirection(uint8_t dir)
+{
+ this->m_display.setFontDirection(dir);
+}
+
+int8_t CPaint::GetAscent()
+{
+ return this->m_display.getAscent();
+}
+
+int8_t CPaint::GetDescent()
+{
+ return this->m_display.getDescent();
+}
+
+void CPaint::SetFontPosBaseline()
+{
+ this->m_display.setFontPosBaseline();
+}
+
+void CPaint::SetFontPosBottom()
+{
+ this->m_display.setFontPosBottom();
+}
+
+void CPaint::SetFontPosTop()
+{
+ this->m_display.setFontPosTop();
+}
+
+void CPaint::SetFontPosCenter()
+{
+ this->m_display.setFontPosCenter();
+}
+
+void CPaint::SetFontRefHeightText()
+{
+ this->m_display.setFontRefHeightText();
+}
+
+void CPaint::SetFontRefHeightExtendedText()
+{
+ this->m_display.setFontRefHeightExtendedText();
+}
+
+void CPaint::SetFontRefHeightAll()
+{
+ this->m_display.setFontRefHeightAll();
+}
+
+uint8_t CPaint::DrawGlyph(uint8_t x, uint8_t y, uint16_t encoding)
+{
+ this->m_display.drawGlyph(x, y, encoding);
+}
+
+uint8_t CPaint::DrawStr(uint8_t x, uint8_t y, const char* s)
+{
+ this->m_display.drawStr(x, y, s);
+}
+
+uint8_t CPaint::DrawUTF8(uint8_t x, uint8_t y, const char* s)
+{
+ this->m_display.drawUTF8(x, y, s);
+}
+
+uint8_t CPaint::DrawExtUTF8(uint8_t x, uint8_t y, uint8_t to_left, const uint16_t *kerning_table, const char* s)
+{
+ this->m_display.drawExtUTF8(x, y, to_left, kerning_table, s);
+}
+
+uint8_t CPaint::GetStrWidth(const char* s)
+{
+ return this->m_display.getStrWidth(s);
+}
+
+uint8_t CPaint::GetUTF8Width(const char* s)
+{
+ return this->m_display.getUTF8Width(s);
+}
+
+uint8_t CPaint::UISelectionList(const char* title, uint8_t start_pos, const char* sl)
+{
+ this->m_display.userInterfaceSelectionList(title, start_pos, sl);
+}
+
+uint8_t CPaint::UIMessage(const char* title1, const char* title2, const char* title3, const char* buttons)
+{
+ this->m_display.userInterfaceMessage(title1, title2, title3, buttons);
+}
+
+uint8_t CPaint::UIInputValue(const char* title, const char* pre, uint8_t* value, uint8_t lo, uint8_t hi, uint8_t digits, const char* post)
+{
+ return this->m_display.userInterfaceInputValue(title, pre, value, lo, hi, digits, post);
+}
+
+void CPaint::LCDHome()
+{
+ this->m_display.home();
+}
+
+void CPaint::LCDClear()
+{
+ this->m_display.clear();
+}
+
+void CPaint::LCDNoDisplay()
+{
+ this->m_display.noDisplay();
+}
+
+void CPaint::LCDDisplay()
+{
+ this->m_display.display();
+}
+
+void CPaint::LCDSetCursor(uint8_t x, uint8_t y)
+{
+ this->m_display.setCursor(x, y);
+}
+
+uint8_t CPaint::LCDGetCursorX()
+{
+ this->m_display.getCursorX();
+}
+
+uint8_t CPaint::LCDGetCursorY()
+{
+ this->m_display.getCursorY();
+}
+
+void CPaint::SleepOn()
+{
+ this->m_display.sleepOn();
+}
+
+void CPaint::SleepOff()
+{
+ this->m_display.sleepOff();
+}
+
+void CPaint::SetColorIndex(uint8_t color_index)
+{
+ this->m_display.setColorIndex(color_index);
+}
+
+uint8_t CPaint::GetColorIndex()
+{
+ this->m_display.getColorIndex();
+}
+
+int8_t CPaint::GetFontAscent()
+{
+ this->m_display.getFontAscent();
+}
+
+int8_t CPaint::GetFontDescent()
+{
+ this->m_display.getFontDescent();
+}
+
+int8_t CPaint::GetMaxCharHeight()
+{
+ this->m_display.getMaxCharHeight();
+}
+
+int8_t CPaint::GetMaxCharWidth()
+{
+ this->m_display.getMaxCharWidth();
+}
+
+/* CControl */
+CControl::CControl(CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig) :
+ m_pMiniDexed(pMiniDexed),
+ m_pGPIOManager(pGPIOManager),
+ m_pConfig(pConfig),
+ m_ppRotaryEncoders(nullptr)
+{
+}
+
+CControl::~CControl()
+{
+ if(this->m_ppRotaryEncoders)
+ {
+ for(int i = 0; i < NUM_CONTROLS; i++)
+ {
+ delete this->m_ppRotaryEncoders[i];
+ }
+
+ delete []this->m_ppRotaryEncoders;
+ }
+}
+
+bool CControl::Initialize()
+{
+ assert(this->m_pConfig);
+
+ if(this->m_pConfig->GetEncoderEnabled())
+ {
+ this->m_ppRotaryEncoders = new CKY040*[4];
+ for(int i = 0; i < NUM_CONTROLS; i++) {
+ this->m_ppRotaryEncoders[i] = new CKY040(
+ this->m_pConfig->GetEncoderPinClock(),
+ this->m_pConfig->GetEncoderPinData(),
+ this->m_pConfig->GetEncoderPinSwitch(),
+ this->m_pGPIOManager
+ );
+ }
+ }
+
+ return true;
+}
+
+CKY040& CControl::operator[](size_t index)
+{
+ return *this->m_ppRotaryEncoders[index % NUM_CONTROLS];
+}
+
+/* CScreen */
+CScreen::CScreen(unsigned id, const char* name, unsigned nPages) :
+ m_id(id),
+ m_name(name),
+ m_nPages(nPages),
+ m_currentScrollPage(0),
+ m_isDirty(false)
+{
+}
+
+CScreen::~CScreen()
+{
+}
+
+void CScreen::Activate(CScreen& nxtScreen)
+{
+ nxtScreen.SetDirty(true);
+}
+
+void CScreen::Activate()
+{
+ CScreen::Activate(*this);
+}
+
+unsigned CScreen::ScrollLeftPage()
+{
+ unsigned nxPage = (this->m_currentScrollPage + 1) % this->m_nPages;
+ this->Dirty(this->m_currentScrollPage != nxPage);
+ this->m_currentScrollPage = nxPage;
+
+ return this->m_currentScrollPage;
+}
+
+unsigned CScreen::ScrollRightPage()
+{
+ unsigned nxPage = (this->m_currentScrollPage + this->m_nPages - 1) % this->m_nPages;
+ this->Dirty(this->m_currentScrollPage != nxPage);
+ this->m_currentScrollPage = nxPage;
+
+ return this->m_currentScrollPage;
+}
+
+unsigned CScreen::CurrentScrollPage()
+{
+ return this->m_currentScrollPage;
+}
+
+unsigned CScreen::ScrollToPage(unsigned pageNum)
+{
+ unsigned nxPage = pageNum % this->m_nPages;
+ this->Dirty(this->m_currentScrollPage != nxPage);
+ this->m_currentScrollPage = nxPage;
+
+ return this->m_currentScrollPage;
+}
+
+void CScreen::SetDirty(bool isDirty)
+{
+ this->m_isDirty = isDirty;
+}
+
+void CScreen::Dirty(bool isDirty)
+{
+ this->m_isDirty |= isDirty;
+}
+
+bool CScreen::IsDirty()
+{
+ return this->m_isDirty;
+}
+
+void CScreen::Display(CPaint& paint)
+{
+ if(this->IsDirty())
+ {
+ this->Paint(paint);
+ }
+}
+
+
+CScreenManager& CScreenManager::GetInstance()
+{
+ static CScreenManager inst;
+
+ return inst;
+}
+
+CScreenManager::CScreenManager() :
+ m_screenMap()
+{
+}
+
+CScreenManager::~CScreenManager()
+{
+}
+
+void CScreenManager::Register(CScreen* pScreen)
+{
+ this->m_screenMap[pScreen->m_id] = pScreen;
+}
+
+CScreen& CScreenManager::operator[](unsigned index)
+{
+ return *(this->m_screenMap[index]);
+}
+
+CScreen& CScreenManager::Activate(unsigned screenId)
+{
+ CScreen& nxtScreen = (*this)[screenId];
+ CScreen::Activate(nxtScreen);
+
+ return nxtScreen;
+}
diff --git a/src/ui.h b/src/ui.h
new file mode 100644
index 0000000..bf3cd3b
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,242 @@
+//
+// minidexed.h
+//
+// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
+// Copyright (C) 2022 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 _ui_h
+#define _ui_h
+
+#define U8X8_USE_PINS 1
+
+#include