Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Recommended reading to get you started:
| GARLIC | NO | NO |NO | No longer maintained, use Portmaster|
| GARLICPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)|
| RG35XXPLUS | MAYBE | NO | YES | Port by [Simotek](http://simotek.net)|
| RK3566 | MAYBE | YES | YES | ROCKNIX handhelds (Powkiddy RGB30 etc.), via the ALSA sequencer [See notes](docs/RK3566_PORT.md) |
| MACOS | YES | YES | MAYBE | Port by [clsource](https://genserver.social/clsource) |

* **MIDI functionality __greatly__ depends on kernel support, please feature request your favourite OS maintainer =)**
Expand Down
474 changes: 474 additions & 0 deletions docs/RK3566_PORT.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions projects/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ BEAGLEBOARDDIRS := $(LINUXDIRS) $(DUMMYMIDIDIRS) $(RTAUDIODIRS) $(SDLDIRS)
DEBDIRS := $(DBDIRS) $(JACKDIRS) $(RTAUDIODIRS) $(RTMIDIDIRS) $(SDLDIRS)
RASPIDIRS := $(DBDIRS) $(RTAUDIODIRS) $(RTMIDIDIRS) $(SDLDIRS)
RG35XXPLUSDIRS := $(LINUXDIRS) $(DUMMYMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS)
RK3566DIRS := $(LINUXDIRS) $(RTMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS)
STEAMDIRS := $(LINUXDIRS) $(JACKDIRS) $(RTAUDIODIRS) $(RTMIDIDIRS) $(SDLDIRS)
X64DIRS := $(LINUXDIRS) $(RTMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS)
X86DIRS := $(LINUXDIRS) $(RTMIDIDIRS) $(SDL2DIRS) $(SDL2AUDIODIRS)
Expand Down Expand Up @@ -327,6 +328,7 @@ DEBFILES := $(DBFILES) $(RTAUDIOFILES) $(RTMIDIFILES) $(JACKFILES)
BEAGLEBOARDFILES := $(LINUXFILES) $(DUMMYMIDIFILES)
RASPIFILES := $(DBFILES) $(RTAUDIOFILES) $(RTMIDIFILES)
RG35XXPLUSFILES := $(LINUXFILES) $(SDLAUDIOFILES) $(DUMMYMIDIFILES)
RK3566FILES := $(LINUXFILES) $(SDLAUDIOFILES) $(RTMIDIFILES)
STEAMFILES := $(LINUXFILES) $(RTAUDIOFILES) $(RTMIDIFILES) $(JACKFILES)
X64FILES := $(LINUXFILES) $(RTMIDIFILES) $(SDLAUDIOFILES)
X86FILES := $(LINUXFILES) $(RTMIDIFILES) $(SDLAUDIOFILES)
Expand Down
107 changes: 107 additions & 0 deletions projects/Makefile.RK3566
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
-include $(PWD)/rules_base

#---------------------------------------------------------------------------------
# LittleGPTracker - RK3566 / ROCKNIX port
#
# Targets RK3566 based handhelds running ROCKNIX (Powkiddy RGB30, Anbernic
# RG-ARC, Gameforce Chi, ...). Cross-compiles on an x86_64 host but links
# against the *target's own* SDL2, so the only artifact that has to be copied
# to the device is the executable - no bundled libraries, no bundled fonts,
# no bundled libc.
#
# Requirements on the build host:
# * Arm GNU Toolchain aarch64-none-linux-gnu with glibc 2.38, to match the
# glibc shipped in ROCKNIX (GLIBC_2.38 is the newest versioned symbol
# the device exports; anything newer will not load).
# * SDL2 headers matching the device's runtime (SDL 2.30.x) plus a linker
# stub for the device's libSDL2.so.
#
# Both are located with RK3566_TOOLCHAIN / RK3566_SYSROOT and can be pointed
# somewhere else from the command line:
#
# make PLATFORM=RK3566 RK3566_SYSROOT=/opt/rocknix-sysroot
#
# See docs/RK3566_PORT.md for how the sysroot is assembled.
#---------------------------------------------------------------------------------

RK3566_TOOLCHAIN ?= /devel/src/.rk3566-port/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu
RK3566_SYSROOT ?= /devel/src/.rk3566-port/sysroot

PREFIX := $(RK3566_TOOLCHAIN)/bin/aarch64-none-linux-gnu-
CROSS_COMPILE := $(PREFIX)
TOOLPATH := $(RK3566_TOOLCHAIN)/bin

CC := $(CROSS_COMPILE)gcc
CXX := $(CROSS_COMPILE)g++
STRIP := $(CROSS_COMPILE)strip

#---------------------------------------------------------------------------------
# config
#
# _64BIT : target is LP64, the tracker's default is 32bit assumptions
# CPP_MEMORY : use the C++ allocator instead of the platform allocator
# SDL2 : use the SDL2 GUI/timer adapters rather than the SDL1.2 ones
# SDLAUDIO : audio out through SDL2 (which goes to ALSA on ROCKNIX)
# RTMIDI : MIDI through the bundled RtMidi
# __LINUX_ALSA__ / __LINUX_ALSASEQ__ : select RtMidi's ALSA sequencer backend.
# RtMidi 1.0.8 actually guards that code with the ALSASEQ
# spelling, while the ALSA spelling is what the rest of the
# desktop makefiles pass; both are defined so this target
# matches X64/RASPI. ALSA seq is how the kernel presents USB
# MIDI interfaces to userspace.
# _NO_JACK_ : do not probe for a JACK server
#
# FFMPEG_ENABLED is deliberately NOT set: it only gates the ffmpeg based
# sample import in InstrumentView and would add a large dependency for a
# feature that needs a keyboard and a file dialog to be useful.
#---------------------------------------------------------------------------------

DEFINES := \
-DPLATFORM_$(PLATFORM) \
-D_64BIT \
-DBUFFERED \
-DCPP_MEMORY \
-DHAVE_STDINT_H \
-D_NDEBUG \
-D_NO_JACK_ \
-DSDL2 \
-DSDLAUDIO \
-DRTMIDI \
-D__LINUX_ALSA__ \
-D__LINUX_ALSASEQ__

# The tree mixes <SDL2/SDL.h> (SDL2 adapters) and <SDL/SDL.h> (legacy SDL1.2
# adapters), so both the SDL2 directory itself and its parent have to be on the
# include path. A "SDL" symlink next to the real "SDL2" directory keeps the few
# legacy includes that are still reachable in this configuration resolvable.
SDL_CFLAGS := -I$(RK3566_SYSROOT)/usr/include/SDL2 -I$(RK3566_SYSROOT)/usr/include -D_REENTRANT
SDL_LIBS := -lSDL2

# RtMidi's ALSA backend talks to /dev/snd/seq through libasound. The sysroot
# carries the device's own libasound.so.2 plus matching headers, so MIDI needs
# no extra runtime dependency on the device.
ALSA_LIBS := -lasound

#---------------------------------------------------------------------------------
# optimization
#
# RK3566 is a quad Cortex-A55. -fno-strict-aliasing is kept because the
# tracker predates strict aliasing rules and type-punning through the mixer
# would otherwise be miscompiled at -O3.
#---------------------------------------------------------------------------------

OPT_FLAGS := -O3 -mcpu=cortex-a55 -mtune=cortex-a55 -fno-strict-aliasing

INCLUDES := $(SDL_CFLAGS) -I$(PWD)/../sources
CFLAGS := $(DEFINES) $(INCLUDES) $(OPT_FLAGS) -Wall
CXXFLAGS := $(CFLAGS) -std=gnu++03
LIBS := -L$(RK3566_SYSROOT)/usr/lib \
-Wl,--allow-shlib-undefined \
-Wl,-rpath-link,$(RK3566_SYSROOT)/usr/lib \
$(SDL_LIBS) $(ALSA_LIBS) -lpthread -lm -ldl

OUTPUT = ../lgpt-rk3566
EXTENSION := elf

%.elf: $(OFILES)
$(CXX) $(LDFLAGS) -o $@ $(OFILES) $(LIBS)
31 changes: 31 additions & 0 deletions projects/resources/RK3566/LittleGPTracker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/bash
#
# LittleGPTracker / Little Piggy Tracker - ROCKNIX (RK3566) launch script
#
# This is the script EmulationStation shows in the "Ports" menu. Everything
# the tracker needs - the binary, config.xml and mapping.xml - sits next to it
# in this directory, and the tracker keeps its projects and samples here too.
#
# Ported by cross-compiling against the device's own SDL2; see
# docs/RK3566_PORT.md in the source tree for how to rebuild it.

# ROCKNIX's /etc/profile.d/050-sway.conf already exports WAYLAND_DISPLAY,
# XDG_RUNTIME_DIR, SDL_VIDEODRIVER=wayland and SDL_AUDIODRIVER=pulseaudio,
# which is exactly the environment the tracker needs. Do not second-guess it
# here: anything exported before this line gets overwritten anyway.
. /etc/profile

# Resolve this script's directory and work from there: the tracker treats the
# current directory as "root:", where projects and samples are read from and
# written to. HOME is left alone, so PulseAudio and SDL keep their state in
# /storage rather than scattering dotfiles through the port directory.
progdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
cd "$progdir" || exit 1

# The tracker logs to stdout; capture it beside the binary for troubleshooting.
rm -f log.txt
./lgpt-rk3566.elf > log.txt 2>&1

# The tracker writes projects to the SD card; make sure they land before
# EmulationStation takes the screen back.
sync
126 changes: 126 additions & 0 deletions projects/resources/RK3566/config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<CONFIG>
<!--
LittleGPTracker configuration for RK3566 / ROCKNIX handhelds.

The panel on these devices (Powkiddy RGB30, Anbernic RG-ARC, ...) is
720x720 while the tracker always draws a 320x240 screen, so the drawn
screen is scaled up to fit. No SCREENMULT is set here, which means
"fill the panel": 2.25x across and 3x down. That is as large as the
text can be made, and on a panel this dense the alternative - whole
multiples only, which cap out at 2x and leave black borders - is
uncomfortably small to read.

To keep the original 4:3 proportions instead and accept smaller text
with black bars, set:

<SCREENMULT value='2'/>

which presents the screen at exactly 2x, centred (640x480).
-->
<FULLSCREEN value='YES'/>

<!--
Show the project picker on every start instead of jumping straight
into the last project. That picker is the only place the tracker
offers an "Exit" button, so leaving this at NO guarantees the UI
always offers a way out of the application.
-->
<AUTO_LOAD_LAST value='NO'/>

<!-- Joystick/keyboard auto repeat, in milliseconds. -->
<KEYDELAY value='200'/>
<KEYREPEAT value='100'/>

<!--
Quit the tracker by holding these SDL joystick buttons together.
On this pad 8 is Select and 9 is Start, so Select+Start quits - the
same combination ROCKNIX uses to leave an emulator.

This exists because the tracker's only built-in quit control is the
"Exit" button on the project picker, which cannot be reached once a
project is loaded, and a handheld has no window to close.
-->
<QUITBUTTONS value='8,9'/>

<!-- '0':original '1':digital '2':monster 'CUSTOM': load custom_font.xml -->
<FONTTYPE value='0'/>

<!--
=========================================================================
THEME: ayu dark
=========================================================================

Taken from the ayu dark VS Code theme, so the tracker's slots follow the
roles ayu itself uses rather than an approximation of its palette:

BACKGROUND editor.background
FOREGROUND editor.foreground
CURSORCOLOR editorCursor.foreground
BORDER editor.findMatchBackground / accent tint (list.highlight)
ROWCOLOR1 editorLineNumber.activeForeground
ROWCOLOR2 editorLineNumber.foreground, ie 5a6378 at alpha a6
composited over the background -> 404758
COL_TITLE activityBarTop.foreground
the rest the ayu token colours, by their syntax role

ayu uses one accent (the gold E6B450) for the cursor, the border and the
active highlights, so CURSORCOLOR and BORDER sharing it is deliberate.

Sources: https://github.com/ayu-theme/ayu-colors (MIT) and
https://github.com/ayu-theme/vscode-ayu (MIT). The tracker reads these
once at startup, so a change needs a relaunch. Delete this block to go
back to the built-in purple theme.

Contrast against the background is noted where a value is on the dim
side, since this panel is dense and easy to under-light.
-->
<BACKGROUND value='10141C'/> <!-- editor.background -->
<FOREGROUND value='BFBDB6'/> <!-- editor.foreground 9.8:1 -->
<BORDER value='E6B450'/> <!-- accent tint -->
<CURSORCOLOR value='E6B450'/> <!-- editorCursor.foreground -->
<PLAYCOLOR value='AAD94C'/> <!-- token green -->
<MUTECOLOR value='F07178'/> <!-- token red -->
<HICOLOR1 value='FF8F40'/> <!-- token orange (keywords) -->
<HICOLOR2 value='FFB454'/> <!-- token yellow (functions) -->
<ROWCOLOR1 value='5A6378'/> <!-- line number, active 3.1:1 -->
<ROWCOLOR2 value='404758'/> <!-- line number, normal 2.0:1 -->
<MAJORBEAT value='697184'/> <!-- activityBarTop.fg 3.8:1 -->
<COL_TITLE value='697184'/> <!-- activityBarTop.fg -->
<SONGVIEW_FE value='95E6CB'/> <!-- token teal -->
<SONGVIEW_00 value='5A6673'/> <!-- comment grey 3.1:1 -->
<CONSOLE value='AAD94C'/> <!-- token green -->

<!--
=========================================================================
MIDI INPUT
=========================================================================

Open every MIDI input that is present, instead of naming one. The
tracker matches MIDICTRLDEVICE as a prefix, and a driver appends its
own port number, so naming a device means knowing it in advance
("Midi Through" matches "Midi Through:0"). On a handheld the name of
whatever keyboard is plugged in is not known when this file is
written, and "*" is the wildcard that skips the match.

Input shows up to the tracker as the controller source "midi", so an
interface only does something once mapping.xml maps one of its
events, for example:

<MAP src="midi:all:0:note:60" dst="/event/start" />

which is MIDI channel 1, note 60. The middle field is the device
name as listed in log.txt, or "all" to accept any device. cc, pb,
pc, at and note are the event types that can be mapped.

MIDI OUT is chosen per project, in the project view's "MIDI:" field.
Both directions need an ALSA sequencer port to talk to, which is what
a USB MIDI interface creates when it is plugged in.
-->
<MIDICTRLDEVICE value='*'/>

<!--
Set DUMPEVENT to YES to print every key/button/axis event to log.txt.
That is how mapping.xml below was produced.
-->
<!-- <DUMPEVENT value='YES'/> -->
</CONFIG>
72 changes: 72 additions & 0 deletions projects/resources/RK3566/fetch-demo-song.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash
#
# Fetch a demo song and install it into the port directory.
#
# The demo songs ship inside the official LittleGPTracker release archives,
# alongside samplelib. They are not committed to this repository: the demo
# projects are third party musical works, and the tracker's .gitignore
# deliberately excludes *.wav and *.dat (upstream drops them into
# projects/resources/packaging/ at packaging time instead of committing them).
# Downloading them from the project's own release keeps the provenance obvious.
#
# Usage:
# ./fetch-demo-song.sh [PROJECT] [DEST] [TAG]
#
# PROJECT which demo to install (default: lgpt_Bootloop-FastJump)
# DEST port directory on the device (default: /storage/roms/ports/LittleGPTracker)
# TAG release to take it from (default: 1.6.0-bacon20)
#
# Available demo songs in the 1.6.0-bacon20 release, with the size of the song
# grid and how much of it is used (8 channels):
#
# lgpt_Bootloop-FastJump 56 rows, 73 chains, 8 channels 12 MB
# lgpt_Luce-COMPSENTRY 24 rows, 8 chains, 4 channels 14 MB
# lgpt_Float-Fi-WildDope 16 rows, 29 chains, 8 channels 8.5 MB
# lgpt_djdiskmachine-SereneDream 16 rows, 24 chains, 7 channels 2.2 MB
# lgpt_BA0BAB_D1BBB5 8 rows, 25 chains, 7 channels 2.1 MB
#
# Run this on the device (it has curl and unzip), or on a host with the port
# directory mounted. The whole release archive is ~78 MB, most of it samplelib,
# so the download is the slow part.
#
set -euo pipefail

PROJECT="${1:-lgpt_Bootloop-FastJump}"
DEST="${2:-/storage/roms/ports/LittleGPTracker}"
TAG="${3:-1.6.0-bacon20}"

URL="${LGPT_RELEASE_URL:-https://github.com/djdiskmachine/LittleGPTracker/releases/download/${TAG}/LGPT-X64-${TAG}.zip}"

if [ ! -d "$DEST" ]; then
echo "port directory not found: $DEST" >&2
exit 1
fi

WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT

echo "==> downloading $TAG (about 78 MB, this takes a while)"
curl -fSL --progress-bar -o "$WORK/lgpt.zip" "$URL"

echo "==> extracting $PROJECT"
if ! unzip -l "$WORK/lgpt.zip" "$PROJECT/*" >/dev/null 2>&1; then
echo "no such demo project in $TAG: $PROJECT" >&2
echo "available:" >&2
unzip -l "$WORK/lgpt.zip" | awk '{print $4}' | grep -oE '^lgpt_[^/]+' | sort -u >&2
exit 1
fi
unzip -q -o "$WORK/lgpt.zip" "$PROJECT/*" -d "$WORK"

echo "==> installing into $DEST"
rm -rf "${DEST:?}/$PROJECT"
cp -r "$WORK/$PROJECT" "$DEST/$PROJECT"

# Point the tracker at it, so enabling AUTO_LOAD_LAST later opens the demo
# rather than nothing.
printf '%s\n' "$DEST/$PROJECT" > "$DEST/last_project"

echo
echo "installed $(du -sh "$DEST/$PROJECT" | cut -f1):"
ls "$DEST/$PROJECT"
echo
echo "Start the tracker and pick '${PROJECT#lgpt_}' from the project list."
Binary file added projects/resources/RK3566/lgpt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading