Skip to content
probonopd edited this page Nov 17, 2024 · 24 revisions

This page contains information relevant for developers.

Developing in the cloud

This is the quickest way to start coding without having to set up software locally. Click on

image

Paste (Command-SHIFT-V) the following:

git checkout i2c # if you want to edit a particular branch
git submodule update --init --recursive
sh -ex submod.sh # Get particular git commits of the submodules
wget -q https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz
tar xf *-aarch64-none-elf.tar.xz
# wget -q https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz
# tar xf *-arm-none-eabi.tar.xz
export PATH=$(readlink -f ./gcc-*aarch64-none*/bin/):$PATH
RPI=3 bash -ex build.sh

# To rebuild
cd src/
make -j4

Building locally

Normal users do not need to build the source code, as compiled versions are provided for download. If you are a developer and want to build the source code yourself, you can use the following example, e.g., to build for Raspberry Pi 4 on a Ubuntu 20.04 build system. See build.yml for complete build steps that create versions for Raspberry Pi 1, 2, 3,and 4 in 32-bit and 64-bit as required.

# Choose your RPi
export RPI=4

git clone https://github.com/probonopd/MiniDexed
cd MiniDexed
mkdir -p kernels sdcard

# Recursively pull git submodules
git submodule update --init --recursive

# Get particular git commits of the submodules
sh -ex submod.sh

# 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 ../MiniDexed_$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

Booting over the network

https://github.com/probonopd/CircleNetboot can be used to boot images over the network without the need to swap SD cards for each build.

Logging

Use mLogger.Write() like in this example to output diagnostic messages to the HDMI screen during development:

https://github.com/probonopd/MiniDexed/blob/8be0781b492149c5bbfa507e1f1d17d1a19b81ed/src/circle_stdlib_app.h#L196-L197

Don't output debug messages during normal operation, as this can negatively impact the sound quality on some Raspberry Pi models.

HINT: to better debug early events, place only one "sysex voice" to have more messages printed.

Different log levels can be used. There is an option loglevel= in the file cmdline.txt on the SD card which controls the amount of generated log messages. Please note that in MiniDexed, log messages will not be displayed from IRQ_LEVEL by default, because it uses the REALTIME option. For debugging purpose you may have to disable this option in build.sh before build if you want to see messages from IRQ handlers.

Naming conventions

MiniDexed is based on Circle, a C++ bare metal environment for Raspberry Pi with USB (32 and 64 bit). Thanks to @rsta2 and contributors for this useful framework, without which MiniDexed would not exist.

The following naming conventions are used:

  • Identifiers for types and variables will be written this way: "MyExampleIdentifier" (each word starts with an uppercase letter).
  • Class names start with a "C", other types (struct, enum) with a "T".
  • Member variable names of a class start with a "m_", static variables in a class definition with a "s_".
  • Variable names get a prefix, which specify its (simple) standard type. This prefix follows the "m_" or "s_", if it is used. Variables of complex types do not have such prefix (except a "p" for pointer). Only one of these prefixes is used (i.e. "puch" for a pointer to an unsigned char is not used, use only "p" instead):
uch	unsigned char, u8, uint8_t
us	unsigned short u16, uint16_t
ul	unsigned long
ch	signed char, s8, int8_t
s	signed short, s16, int16_t
l	signed long
n	unsigned, int, u32, s32, uint32_t, int32_t, or any other (non-float) numeric variable
f	float, double
b	bool, boolean
p	Pointer to a simple or complex type

Synth_Dexed

MiniDexed is calling into Synth_Dexed for the actual synthesizer functionality. Thanks to @dcoredump and contributors for this useful library, without which MiniDexed would not exist.

Updating Synth_Dexed git submodule

From time to time, developers need to update a git submodule, such as Synth_Dexed. If the submodule should be updated on an incoming pull request, then one actually needs to do the change in the respository and on the branch from which the pull request originates (example: a pull request came from https://github.com/rsta2/MiniDexed/, branch enable-filter and we want to update the Synth_Dexed git submodule to c58ac7c):

git clone https://github.com/rsta2/MiniDexed/
cd MiniDexed
git checkout enable-filter
git submodule update --init --recursive
cd Synth_Dexed
git fetch
git checkout c58ac7c
cd ..
git add Synth_Dexed
git commit -m "Update Synth_Dexed"
git push origin enable-filter

MiniDexed Scheduling and Architecture

On a V1 Raspberry Pi (single core) naturally all functions have to be run from within the same core process, but on a multi-core Raspberry Pi, the cores are used as follows:

  • Core 0: Initalization; IO (MIDI, buttons, encoders, etc) and user interface handling.
  • Core 1: Two tone generators; mixing; effects; audio output
  • Core 2: Three tone generators
  • Core 3: Three tone generators

The following are the main code modules and classes to make all this happen:

  • main.cpp: starts the Circle kernel.
  • kernel.cpp: the main boot initialization code and the main Run process.
  • minidexed.cpp: the main synthesizer logic: key functions being Initialize(), Process(), Run() (if on a multi-core Raspberry Pi), and ProcessSound().
  • userinterface.cpp: handles the main UI IO and display: key functions being Initialize(), Process(), DisplayWrite() and event handlers for the encoder and buttons.
  • uimenu.cpp: the main UI event handler that either acts on menu events from the UI code; navigates through the user interface menus; or acts on menu items Handler() functions.

The main threads of execution and linkage are shown semi-graphically below.

MiniDexed-Structure