- Introduction
- Setup
- Hardware
- Initial Configuration
- Compilation Method 1: Native Compilation on the Raspi
- Compilation Method 2: Cross-compilation on your computer
- Installation and launch
- Logs
If you want to modify the software that runs on a Haxophone, you will need to setup a development environment. There are many different options on how to do that, here I document a few different approaches I tried with different levels of success.
The first step is that you will need a way to connect your Raspberry Pi to your computer.
On the Raspberry Pi 3/4, this can be Wi-Fi or Ethernet. On the Pi Zero W, Wi-Fi. On the Pi Zero, you will need an USB network adapter.
If you don't have a network around, you can also use a serial console. The Haxophone HAT exposes the serial console signals on connector J4. The pins match the same pinout as pins 6,8,10 on the Raspberry Pi Header. So, if you had a tty serial cable that worked on the PI, it will also work on the J4 connector when the HAT is attached. Note that the serial console will not work if Bluetooth is enabled on the Raspi, so you probably do not want to use the serial console afterall.
For the next sections, we will assume that you are able to get a Linux prompt on the Raspberry Pi. For additional help, you can refer to Raspberry Pi documentation
Highly recommended: use a USB drive for your development and keep your SD Card read-only most of the time.
-
Flash image onto Raspberry Pi. For faster boot, use the Lite version of the OS (no graphical environment)
-
Pick SSH password.
-
Pick a network-unique hostname (
/etc/hostname
). -
On raspi-config, enable:
ssh
,I2C
and (optional)serial console
-
[RP Zero Only] Enable device-mode USB driver (edit
/boot/config.txt
to add)[all] dtoverlay=dwc2
and add
dwc2
to/etc/modules
-
Enable audio card (edit
/boot/config.txt
to add)# dtparam=audio=on dtoverlay=max98357a,sdmode-pin=4
-
Optionally, disable Wifi and Bluetooth. This seems to improve performance on the RPI Zero.
dtoverlay=disable-wifi dtoverlay=disable-bt
-
Speed up I2C (edit
/boot/config.txt
to add)dtparam=i2c_arm_baudrate=400000
-
Install project dependencies
apt install libfluidsynth-dev git libasound2-dev i2c-tools fluid-soundfont-gm
-
Install latest stable Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Note 1: On Raspberry Pi 4 rustup might detect an incorrect architecture. The RPi 3/4 can run in 32-bit or 64-bit. Check
uname -m
to see whether you are runningaarch64
orarmv7l
. If the later, when installing rust:Current installation options: default host triple: aarch64-unknown-linux-gnu This is incorrect --------^^^^^^^
To fix, pick '2. Customize installation' and set host to:
arm-unknown-linux-gnueabihf
See this issue.
Note 2: On Pi Zeros you might need to increase the size of the swap file or else the installation will be killed by insufficient ram. You do this by:
sudo dphys-swapfile swapoff sudo vi /etc/dphys-swapfile # Change CONF_SWAPSIZE=100 to CONF_SWAPSIZE=512 sudo dphys-swapfile setup sudo dphys-swapfile swapon reboot
-
Automount USB drive, if attached
sudo mkdir /media/usb # for FAT32 formatted drive echo '/dev/sda1 /media/usb vfat defaults,nofail,uid=1000,gid=1000 0 2' >> /etc/fstab # for Linux formatted drive echo '/dev/sda1 /media/usb ext4 defaults,nofail 0 2' >> /etc/fstab
Gotcha: If you created the USB partition with e2fsck 1.47, you might encounter this problem. Avoid it by creating your partition from Raspberry Pi (e.g.
sudo mkfs -t ext4 /dev/sda1
) -
[If using VSCode] Connect via VSCode over ssh to target. This will create folder
/home/pi/.vscode-server
. Move that folder to/media/usb/
-
[If using VSCode] Symlink
.vscode-server
directory to USB drive.ln -sf /media/usb/.vscode-server /home/pi
(This is a workaround for VSCode issue that requires a writable directory under the user's home directory).
-
[Highly recommended] Make SD Card read-only
The SD Card may get corrupted if the Raspberry PI is unplugged while a write operation is in progress. In normal operation, one cannot know if a write is happening before powering off, so a radical solution is to forbid all writes. You can do this easily from
raspi-config
:sudo raspi-config Performance Options -> Overlay Filesystem -> Enable Overlay? Yes -> Make Boot Filesystem Writeable? Yes
The overlay filesystem will make your root filesystem writable but only in a non-persistent way. In other words, you may write files to, say,
/home/pi
, but they will disappear after a reboot.Reverse this steps if you need to make the filesystem writable again, for instance if you need to copy new versions of
haxo001
to the root fs or install new packages.
This works very well on a Raspberry Pi 3 and 4, but it is very slow on the Pi Zero. If you configured the Raspberry Pi image as described in the previous section, compilation is easy:
-
Insert a USB drive and reboot. It should auto-mount under
/media/usb
-
Install keys (under
/media/usb
, not the SD card) and load themssh-agent bash ssh-add id_ed25519
-
Clone
haxo-rs
on the USB drivecd /media/usb git clone git@github.com:cardonabits/haxo-rs.git
-
If you plan to make changes to the code and submit pull requests, configure
git
cd haxo-rs git config --local user.email my@email.com git config --local user.name "My Name" git config --local core.editor vim
-
Compile
cargo build --release
-
Only one
haxo
daemon can be running at a time. Before running your build, you might need to stop the pre-installed daemon if it was launched at boot.systemctl stop haxo
-
Run the tests
cargo test -- --test-threads=1
-
[Optional] Run the interactive tests
cargo test all_keys -- --nocapture --ignored
With this method, we will cross-compile binaries. This means, you will compile on your laptop binary executables for a different architecture. This method is recommended if you are building images for the Pi Zero, as native compilation is too slow.
The process outlined here, but I mostly develop on the Pi 4, so native compilation for me is preferred.
By using a Docker container we can run this method without having to install special packages on your system. It will also work independently of your Operating System.
Using cross, build haxo-rs for target arm-unknown-linux-gnueabihf
You first need to create a container with libfluidsynth
installed and add lib
path to build.rs
. But compilation fails due to uresolved symbols provided by
fluidsynth dependent shared libs
Also a problem: cross
has an issue with targetting the Pi zero
The haxo
daemon is launched by systemd. If you need to install a new version, you need to copy the binary to where systemd expects it.
- Disable overlay (if previously enabled)
- Copy
target/release/haxo001
to/usr/local/bin/haxo001
- Install systemctl service files
cd scripts/systemd sudo ./install.sh
- Re-enable overlay
If you need to modify how systemd launches the haxo
daemon, you will need to
edit /etc/systemd/system/haxo.service
:
[Unit]
Description=haxophone
After=network.target
StartLimitIntervalSec=0
[Service]
Type=idle
Restart=always
RestartSec=1
User=root
Group=audio
WorkingDir=/usr/share/haxo
Environment=RUST_LOG=info
ExecStart=/usr/local/bin/haxo001 \
--notemap-file /usr/share/haxo/notemap.json \
--bank-number 66 \
--sf2-file /usr/share/sounds/sf2/TimGM6mb.sf2
[Install]
WantedBy=multi-user.target
You can inspect logs with
journalctl -u haxo
Oct 11 17:11:17 raspberrypi-one haxo001[641]: Synth created
Oct 11 17:11:17 raspberrypi-one haxo001[641]: Starting haxophone...