first internal commit to continue dev on laptop

pull/293/head
abscisys 2 years ago
parent 0a5ec7d529
commit bdae61102a
  1. 3
      .gitmodules
  2. 1
      .vscode/configurationCache.log
  3. 4
      .vscode/dryrun.log
  4. 3
      .vscode/settings.json
  5. 4
      .vscode/targets.log
  6. 34
      README.md
  7. BIN
      analysis/MenuStructure.xlsx
  8. BIN
      analysis/algorithms.jpg
  9. 515
      getsysex.sh
  10. 49
      incrementalBuild.sh
  11. 23
      rebuild.sh
  12. 72
      setup_dev_env.sh
  13. 26
      src/Makefile
  14. 4
      src/Rules.mk
  15. 122
      src/Synth_Dexed.mk
  16. 292
      src/mididevice.cpp
  17. 525
      src/minidexed.cpp
  18. 66
      src/minidexed.h
  19. 64
      src/screens.cpp
  20. 97
      src/screens.h
  21. 2
      src/sysexfileloader.h
  22. 614
      src/ui.cpp
  23. 242
      src/ui.h
  24. 20
      src/userinterface.cpp
  25. 7
      src/userinterface.h
  26. 237
      src/userinterfaceext.cpp
  27. 73
      src/userinterfaceext.h
  28. 1
      u8g2

3
.gitmodules vendored

@ -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

@ -0,0 +1 @@
{"buildTargets":[],"launchTargets":[],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":[],"compilerArgs":[]},"fileIndex":[]}}

@ -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.

@ -0,0 +1,3 @@
{
"makefile.extensionOutputFolder": "./.vscode"
}

@ -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.

@ -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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

@ -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

@ -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 ..

@ -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!!!"

@ -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

@ -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

@ -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 \

@ -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]

@ -20,16 +20,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <circle/logger.h>
#include "mididevice.h"
#include "minidexed.h"
#include "config.h"
#include <stdio.h>
#include <assert.h>
LOGMODULE ("mididevice");
#define MIDI_NOTE_OFF 0b1000
#define MIDI_NOTE_ON 0b1001
#define MIDI_AFTERTOUCH 0b1010 // TODO
@ -37,25 +33,14 @@ LOGMODULE ("mididevice");
#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_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,87 +97,19 @@ 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++)
{
if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN)
{
// MIDI SYSEX per MIDI channel
uint8_t ucSysExChannel = (pMessage[2] & 0x07);
if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode)
{
LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG);
HandleSystemExclusive(pMessage, nLength, nCable, nTG);
}
}
else
{
if ( m_ChannelMap[nTG] == ucChannel
|| m_ChannelMap[nTG] == OmniMode)
@ -243,55 +162,29 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
m_pSynthesizer->SetVolume (pMessage[2], nTG);
break;
case MIDI_CC_PAN_POSITION:
m_pSynthesizer->SetPan (pMessage[2], nTG);
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;
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);
int bank = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG);
bank = (bank & 0b011111110000000) + pMessage[2];
m_pSynthesizer->BankSelect (bank, 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);
case MIDI_CC_BANK_SUSTAIN:
m_pSynthesizer->setSustain (pMessage[2] >= 64, 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;
@ -313,163 +206,4 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
}
}
}
}
}
m_MIDISpinLock.Release ();
}
void CMIDIDevice::AddDevice (const char *pDeviceName)
{
assert (pDeviceName);
assert (m_DeviceName.empty ());
m_DeviceName = pDeviceName;
assert (!m_DeviceName.empty ());
s_DeviceMap.insert (std::pair<std::string, CMIDIDevice *> (pDeviceName, this));
}
void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG)
{
int16_t sysex_return;
sysex_return = m_pSynthesizer->checkSystemExclusive(pMessage, nLength, nTG);
LOGDBG("SYSEX handler return value: %d", sysex_return);
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;
}
}
void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable, uint8_t nTG)
{
uint8_t voicedump[163];
// Get voice sysex dump from TG
m_pSynthesizer->getSysExVoiceDump(voicedump, nTG);
TDeviceMap::const_iterator Iterator;
// 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());
}
}

@ -23,7 +23,6 @@
#include <circle/pwmsoundbasedevice.h>
#include <circle/i2ssoundbasedevice.h>
#include <circle/hdmisoundbasedevice.h>
#include <circle/gpiopin.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
@ -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<CConfig::ToneGenerators>(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,17 +176,37 @@ bool CMiniDexed::Initialize (void)
if (m_PerformanceConfig.Load ())
{
LoadPerformanceParameters();
}
else
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
SetMIDIChannel (CMIDIDevice::OmniMode, 0);
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);
}
// load performances file list, and attempt to create the performance folder
if (!m_PerformanceConfig.ListPerformances())
// 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
{
LOGERR ("Cannot create internal Performance folder, new performances can't be created");
SetMIDIChannel (CMIDIDevice::OmniMode, 0);
}
// setup and start the sound device
@ -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,11 +805,6 @@ void CMiniDexed::ProcessSound (void)
}
// BEGIN TG mixing
float32_t tmp_float[nFrames*2];
int16_t tmp_int[nFrames*2];
if(nMasterVolume > 0.0)
{
for (uint8_t i = 0; i < CConfig::ToneGenerators; i++)
{
tg_mixer->doAddMix(i,m_OutputLevel[i]);
@ -914,23 +847,14 @@ void CMiniDexed::ProcessSound (void)
// 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; i<nFrames;i++)
{
if(nMasterVolume >0.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);
}
else
arm_fill_q15(0, tmp_int, nFrames * 2);
if (m_pSoundDevice->Write (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,17 +882,10 @@ 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 ());
}

@ -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,11 +155,6 @@ 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];
@ -211,17 +162,6 @@ private:
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;
CPerformanceConfig m_PerformanceConfig;
@ -250,8 +190,6 @@ private:
AudioStereoMixer<CConfig::ToneGenerators>* reverb_send_mixer;
CSpinLock m_ReverbSpinLock;
bool m_bSavePerformance;
};
#endif

@ -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()
{
}

@ -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 <http://www.gnu.org/licenses/>.
//
#ifndef _screens_h
#define _screens_h
#include <ui.h>
#include <minidexed.h>
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

@ -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;

@ -0,0 +1,614 @@
#include "ui.h"
#include <assert.h>
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;
}

@ -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 <http://www.gnu.org/licenses/>.
//
#ifndef _ui_h
#define _ui_h
#define U8X8_USE_PINS 1
#include <map>
#include "minidexed.h"
#include "config.h"
#include <circle/gpiomanager.h>
#include <U8g2lib.h>
#include <sensor/ky040.h>
class CPaint
{
public:
CPaint(uint8_t sdi, uint8_t sda, uint8_t reset);
~CPaint();
void Initialize();
uint32_t GetBusClock();
void SetBusClock(uint32_t clock_speed);
void SetI2CAddress(uint8_t adr);
void EnableUTF8Print();
void DisableUTF8Print();
unsigned Width();
unsigned Height();
void Clear();
void SetPowerSave(uint8_t is_enable);
void SetFlipMode(uint8_t mode);
void SetContrast(uint8_t value);
bool Begin();
void BeginSimple();
void SetMaxClipWindow();
void SetClipWindow(uint8_t clip_x0, uint8_t clip_y0, uint8_t clip_x1, uint8_t clip_y1);
void SendBuffer();
void ClearBuffer();
void FirstPage();
uint8_t NextPage();
uint8_t* GetBufferPtr();
uint8_t GetBufferTileHeight();
uint8_t GetBufferTileWidth();
uint8_t GetPageCurrTileRow();
void SetPageCurrTileRow(uint8_t row);
uint8_t GetBufferCurrTileRow();
void SetBufferCurrTileRow(uint8_t row);
void SetBufferAutoClear(uint8_t mode);
void UpdateDisplayArea(uint8_t tx, uint8_t ty, uint8_t tw, uint8_t th);
void UpdateDisplay();
void RefreshDisplay();
void SetDrawColor(uint8_t color_index);
uint8_t GetDrawColor();
void DrawPixel(uint8_t x, uint8_t y);
void DrawHLine(uint8_t x, uint8_t y, uint8_t w);
void DrawVLine(uint8_t x, uint8_t y, uint8_t h);
void DrawHVLine(uint8_t x, uint8_t y, uint8_t len, uint8_t dir);
void DrawFrame(uint8_t x, uint8_t y, uint8_t w, uint8_t h);
void DrawRFrame(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t r);
void DrawBox(uint8_t x, uint8_t y, uint8_t w, uint8_t h);
void DrawRBox(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t r);
void DrawButtonUTF8(uint8_t x, uint8_t y, uint8_t flags, uint8_t width, uint8_t padding_h, uint8_t padding_v, const char* text);
void DrawCircle(uint8_t x0, uint8_t y0, uint8_t rad, uint8_t opt = U8G2_DRAW_ALL);
void DrawDisc(uint8_t x0, uint8_t y0, uint8_t rad, uint8_t opt = U8G2_DRAW_ALL);
void DrawEllipse(uint8_t x0, uint8_t y0, uint8_t rx, uint8_t ry, uint8_t opt = U8G2_DRAW_ALL);
void DrawFilledEllipse(uint8_t x0, uint8_t y0, uint8_t rx, uint8_t ry, uint8_t opt = U8G2_DRAW_ALL);
void DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
void SetBitmapMode(uint8_t is_transparent);
void DrawBitmap(uint8_t x, uint8_t y, uint8_t cnt, uint8_t h, const uint8_t* bitmap);
void DrawXBM(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t* bitmap);
void DrawXBMP(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t* bitmap);
void DrawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2);
void SetFont(const uint8_t* font);
void SetFontMode(uint8_t is_transparent);
void SetFontDirection(uint8_t dir);
int8_t GetAscent();
int8_t GetDescent();
void SetFontPosBaseline();
void SetFontPosBottom();
void SetFontPosTop();
void SetFontPosCenter();
void SetFontRefHeightText();
void SetFontRefHeightExtendedText();
void SetFontRefHeightAll();
uint8_t DrawGlyph(uint8_t x, uint8_t y, uint16_t encoding);
uint8_t DrawStr(uint8_t x, uint8_t y, const char* s);
uint8_t DrawUTF8(uint8_t x, uint8_t y, const char* s);
uint8_t DrawExtUTF8(uint8_t x, uint8_t y, uint8_t to_left, const uint16_t *kerning_table, const char* s);
uint8_t GetStrWidth(const char* s);
uint8_t GetUTF8Width(const char* s);
uint8_t UISelectionList(const char* title, uint8_t start_pos, const char* sl);
uint8_t UIMessage(const char* title1, const char* title2, const char* title3, const char* buttons);
uint8_t UIInputValue(const char* title, const char* pre, uint8_t* value, uint8_t lo, uint8_t hi, uint8_t digits, const char* post);
void LCDHome();
void LCDClear();
void LCDNoDisplay();
void LCDDisplay();
void LCDSetCursor(uint8_t x, uint8_t y);
uint8_t LCDGetCursorX();
uint8_t LCDGetCursorY();
void SleepOn();
void SleepOff();
void SetColorIndex(uint8_t color_index);
uint8_t GetColorIndex();
int8_t GetFontAscent();
int8_t GetFontDescent();
int8_t GetMaxCharHeight();
int8_t GetMaxCharWidth();
private:
U8G2_SH1122_256X64_F_HW_I2C m_display;
};
#define NUM_CONTROLS 4
class CControl
{
public:
CControl(CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig);
~CControl();
bool Initialize();
CKY040& operator[](size_t index);
private:
CMiniDexed* m_pMiniDexed;
CGPIOManager* m_pGPIOManager;
CConfig* m_pConfig;
CKY040** m_ppRotaryEncoders;
};
class CScreenManager;
class CScreen
{
friend class CScreenManager;
public:
CScreen(unsigned id, const char* name, unsigned nPages = 1);
virtual ~CScreen();
static void Activate(CScreen& nxtScreen);
void Activate();
unsigned ScrollLeftPage();
unsigned ScrollRightPage();
unsigned CurrentScrollPage();
unsigned ScrollToPage(unsigned pageNum);
void SetDirty(bool isDirty);
void Dirty(bool isDirty);
bool IsDirty();
void Display(CPaint& paint);
protected:
virtual void Paint(CPaint& paint) = 0;
private:
const unsigned m_id;
const char* m_name;
const unsigned m_nPages;
unsigned m_currentScrollPage;
bool m_isDirty;
};
class CScreenManager
{
private:
std::map<unsigned, CScreen*> m_screenMap;
CScreenManager();
public:
static CScreenManager& GetInstance();
CScreenManager(CScreenManager const&) = delete;
void operator=(CScreenManager const&) = delete;
~CScreenManager();
void Register(CScreen* pScreen);
CScreen& operator[](unsigned index);
CScreen& Activate(unsigned screenId);
};
#endif

@ -27,10 +27,9 @@
LOGMODULE ("ui");
CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CConfig *pConfig)
CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig)
: m_pMiniDexed (pMiniDexed),
m_pGPIOManager (pGPIOManager),
m_pI2CMaster (pI2CMaster),
m_pConfig (pConfig),
m_pLCD (0),
m_pLCDBuffered (0),
@ -52,9 +51,6 @@ bool CUserInterface::Initialize (void)
assert (m_pConfig);
if (m_pConfig->GetLCDEnabled ())
{
unsigned i2caddr = m_pConfig->GetLCDI2CAddress ();
if (i2caddr == 0)
{
m_pLCD = new CHD44780Device (CConfig::LCDColumns, CConfig::LCDRows,
m_pConfig->GetLCDPinData4 (),
@ -64,12 +60,6 @@ bool CUserInterface::Initialize (void)
m_pConfig->GetLCDPinEnable (),
m_pConfig->GetLCDPinRegisterSelect (),
m_pConfig->GetLCDPinReadWrite ());
}
else
{
m_pLCD = new CHD44780Device (m_pI2CMaster, i2caddr,
CConfig::LCDColumns, CConfig::LCDRows);
}
assert (m_pLCD);
if (!m_pLCD->Initialize ())
@ -176,6 +166,12 @@ void CUserInterface::DisplayWrite (const char *pMenu, const char *pParam, const
LCDWrite (Msg);
}
void CUserInterface::ImmediateLCDWrite (const char *pString)
{
this->LCDWrite(pString);
this->Process();
}
void CUserInterface::LCDWrite (const char *pString)
{
if (m_pLCDBuffered)
@ -219,7 +215,7 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event)
break;
case CKY040::EventSwitchHold:
if (m_pRotaryEncoder->GetHoldSeconds () >= 120)
if (m_pRotaryEncoder->GetHoldSeconds () >= 10)
{
delete m_pLCD; // reset LCD

@ -26,14 +26,13 @@
#include <display/hd44780device.h>
#include <circle/gpiomanager.h>
#include <circle/writebuffer.h>
#include <circle/i2cmaster.h>
class CMiniDexed;
class CUserInterface
{
public:
CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CConfig *pConfig);
CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig);
~CUserInterface (void);
bool Initialize (void);
@ -50,16 +49,16 @@ public:
void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue,
bool bArrowDown, bool bArrowUp);
void ImmediateLCDWrite (const char *pString);
private:
void LCDWrite (const char *pString); // Print to optional HD44780 display
void EncoderEventHandler (CKY040::TEvent Event);
static void EncoderEventStub (CKY040::TEvent Event, void *pParam);
private:
CMiniDexed *m_pMiniDexed;
CGPIOManager *m_pGPIOManager;
CI2CMaster *m_pI2CMaster;
CConfig *m_pConfig;
CHD44780Device *m_pLCD;

@ -0,0 +1,237 @@
//
// userinterface.cpp
//
// 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 <http://www.gnu.org/licenses/>.
//
#include "userinterfaceext.h"
#include "minidexed.h"
#include <circle/logger.h>
#include <circle/string.h>
#include <circle/startup.h>
#include <string.h>
#include <assert.h>
LOGMODULE ("uiext");
CUserInterfaceExt::CUserInterfaceExt (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig)
: m_pMiniDexed (pMiniDexed),
m_pGPIOManager (pGPIOManager),
m_pConfig (pConfig),
m_pLCD (0),
m_pLCDBuffered (0),
m_pRotaryEncoder (0),
m_bSwitchPressed (false),
m_Menu (this, pMiniDexed)
{
}
CUserInterfaceExt::~CUserInterfaceExt (void)
{
delete m_pRotaryEncoder;
delete m_pLCDBuffered;
delete m_pLCD;
}
bool CUserInterfaceExt::Initialize (void)
{
assert (m_pConfig);
if (m_pConfig->GetLCDEnabled ())
{
m_pLCD = new CHD44780Device (CConfig::LCDColumns, CConfig::LCDRows,
m_pConfig->GetLCDPinData4 (),
m_pConfig->GetLCDPinData5 (),
m_pConfig->GetLCDPinData6 (),
m_pConfig->GetLCDPinData7 (),
m_pConfig->GetLCDPinEnable (),
m_pConfig->GetLCDPinRegisterSelect (),
m_pConfig->GetLCDPinReadWrite ());
assert (m_pLCD);
if (!m_pLCD->Initialize ())
{
return false;
}
m_pLCDBuffered = new CWriteBufferDevice (m_pLCD);
assert (m_pLCDBuffered);
LCDWrite ("\x1B[?25l\x1B""d+"); // cursor off, autopage mode
LOGDBG ("LCD initialized");
}
if (m_pConfig->GetEncoderEnabled ())
{
m_pRotaryEncoder = new CKY040 (m_pConfig->GetEncoderPinClock (),
m_pConfig->GetEncoderPinData (),
m_pConfig->GetEncoderPinSwitch (),
m_pGPIOManager);
assert (m_pRotaryEncoder);
if (!m_pRotaryEncoder->Initialize ())
{
return false;
}
m_pRotaryEncoder->RegisterEventHandler (EncoderEventStub, this);
LOGDBG ("Rotary encoder initialized");
}
m_Menu.EventHandler (CUIMenu::MenuEventUpdate);
return true;
}
void CUserInterfaceExt::Process (void)
{
if (m_pLCDBuffered)
{
m_pLCDBuffered->Update ();
}
}
void CUserInterfaceExt::ParameterChanged (void)
{
m_Menu.EventHandler (CUIMenu::MenuEventUpdate);
}
void CUserInterfaceExt::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue,
bool bArrowDown, bool bArrowUp)
{
assert (pMenu);
assert (pParam);
assert (pValue);
CString Msg ("\x1B[H"); // cursor home
// first line
Msg.Append (pParam);
size_t nLen = strlen (pParam) + strlen (pMenu);
if (nLen < CConfig::LCDColumns)
{
for (unsigned i = CConfig::LCDColumns-nLen; i > 0; i--)
{
Msg.Append (" ");
}
}
Msg.Append (pMenu);
// second line
CString Value (" ");
if (bArrowDown)
{
Value = "\x7F"; // arrow left character
}
Value.Append (pValue);
if (bArrowUp)
{
if (Value.GetLength () < CConfig::LCDColumns-1)
{
for (unsigned i = CConfig::LCDColumns-Value.GetLength ()-1; i > 0; i--)
{
Value.Append (" ");
}
}
Value.Append ("\x7E"); // arrow right character
}
Msg.Append (Value);
if (Value.GetLength () < CConfig::LCDColumns)
{
Msg.Append ("\x1B[K"); // clear end of line
}
LCDWrite (Msg);
}
void CUserInterfaceExt::ImmediateLCDWrite (const char *pString)
{
this->LCDWrite(pString);
this->Process();
}
void CUserInterfaceExt::LCDWrite (const char *pString)
{
if (m_pLCDBuffered)
{
m_pLCDBuffered->Write (pString, strlen (pString));
}
}
void CUserInterfaceExt::EncoderEventHandler (CKY040::TEvent Event)
{
switch (Event)
{
case CKY040::EventSwitchDown:
m_bSwitchPressed = true;
break;
case CKY040::EventSwitchUp:
m_bSwitchPressed = false;
break;
case CKY040::EventClockwise:
m_Menu.EventHandler (m_bSwitchPressed ? CUIMenu::MenuEventPressAndStepUp
: CUIMenu::MenuEventStepUp);
break;
case CKY040::EventCounterclockwise:
m_Menu.EventHandler (m_bSwitchPressed ? CUIMenu::MenuEventPressAndStepDown
: CUIMenu::MenuEventStepDown);
break;
case CKY040::EventSwitchClick:
m_Menu.EventHandler (CUIMenu::MenuEventBack);
break;
case CKY040::EventSwitchDoubleClick:
m_Menu.EventHandler (CUIMenu::MenuEventSelect);
break;
case CKY040::EventSwitchTripleClick:
m_Menu.EventHandler (CUIMenu::MenuEventHome);
break;
case CKY040::EventSwitchHold:
if (m_pRotaryEncoder->GetHoldSeconds () >= 10)
{
delete m_pLCD; // reset LCD
reboot ();
}
break;
default:
break;
}
}
void CUserInterfaceExt::EncoderEventStub (CKY040::TEvent Event, void *pParam)
{
CUserInterfaceExt *pThis = static_cast<CUserInterfaceExt *> (pParam);
assert (pThis != 0);
pThis->EncoderEventHandler (Event);
}

@ -0,0 +1,73 @@
//
// userinterface.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 <http://www.gnu.org/licenses/>.
//
#ifndef _userinterface_h
#define _userinterface_h
#include "config.h"
#include "uimenu.h"
#include <sensor/ky040.h>
#include <display/hd44780device.h>
#include <circle/gpiomanager.h>
#include <circle/writebuffer.h>
class CMiniDexed;
class CUserInterfaceExt
{
public:
CUserInterfaceExt (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig);
~CUserInterfaceExt (void);
bool Initialize (void);
void Process (void);
void ParameterChanged (void);
// Write to display in this format:
// +----------------+
// |PARAM MENU|
// |[<]VALUE [>]|
// +----------------+
void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue,
bool bArrowDown, bool bArrowUp);
void ImmediateLCDWrite (const char *pString);
private:
void LCDWrite (const char *pString); // Print to optional HD44780 display
void EncoderEventHandler (CKY040::TEvent Event);
static void EncoderEventStub (CKY040::TEvent Event, void *pParam);
private:
CMiniDexed *m_pMiniDexed;
CGPIOManager *m_pGPIOManager;
CConfig *m_pConfig;
CHD44780Device *m_pLCD;
CWriteBufferDevice *m_pLCDBuffered;
CKY040 *m_pRotaryEncoder;
bool m_bSwitchPressed;
CUIMenu m_Menu;
};
#endif

@ -0,0 +1 @@
Subproject commit 1ccf4cb051c9fe84d455e3cdcf18267c4f90388f
Loading…
Cancel
Save