Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0349a22
feat(satellaview): add Satellaview+ component
XargonWan Apr 26, 2026
0955630
feat(satellaview): add game launcher scripts and gamelist for Satella…
XargonWan Apr 27, 2026
6579bb2
feat(satellaview): update component recipe to include additional asse…
XargonWan Apr 27, 2026
cc488e1
feat(satellaview): implement gamelist merging function and update lau…
XargonWan Apr 27, 2026
ce2ff3d
feat(satellaview): update TODO with snes9x configuration details and …
XargonWan Apr 27, 2026
1da8c80
feat(satellaview): add TODO file for Satellaview+ media assets
XargonWan Apr 27, 2026
cc05233
refactor(satellaview_plus): satellaview plus is now satellaview_pklus…
XargonWan Apr 27, 2026
701944b
feat(satellaview): implement command-based launcher for Satellaview+ …
XargonWan Apr 27, 2026
48b7d65
feat(satellaview): add libgiomm-2.4.so.1 and libglibmm-2.4.so.1 libar…
XargonWan Apr 27, 2026
2722c05
feat(satellaview): add additional file source for library assets in c…
XargonWan Apr 27, 2026
d96c527
feat(satellaview): update LD_LIBRARY_PATH and change asset source typ…
XargonWan Apr 27, 2026
5b536d9
feat(satellaview): add Snes9x configuration setup and new configurati…
XargonWan Apr 27, 2026
8f8c6ce
feat(satellaview): enhance component preparation with logging and dir…
XargonWan Apr 27, 2026
c3e0d2c
feat(satellaview): fix ROM path check and streamline environment vari…
XargonWan Apr 27, 2026
eb360a5
feat(satellaview): set download location in Satellaview+ configuratio…
XargonWan Apr 27, 2026
f5e035c
feat(satellaview): update satellaview_plus_satdata_path to point to t…
XargonWan Apr 27, 2026
06d08a5
feat(satellaview): enable fullscreen mode on ROM open in snes9x confi…
XargonWan Apr 27, 2026
3e6afc5
feat(satellaview): implement symlink workaround for satdata before la…
XargonWan Apr 27, 2026
6e683ec
feat(satellaview): refactor download path variable and update symlink…
XargonWan Apr 27, 2026
c5f0f28
Add new media assets for Satellaview Plus
XargonWan Apr 27, 2026
cfca275
feat(satellaview): populate ES-DE media assets during component prepa…
XargonWan Apr 27, 2026
b7fb001
feat(satellaview): add abxy button swap presets for Joypad configurat…
XargonWan May 14, 2026
5750345
fix(satellaview): remove redundant directory entries from component r…
XargonWan May 14, 2026
d039255
feat(satellaview): update ROM not found error message and add MD5 che…
XargonWan May 14, 2026
ddcdfd6
feat(satellaview): reorganize presets_actions for abxy button swap in…
XargonWan May 14, 2026
7e472e5
feat(satellaview): add es_de_gamelist_entries to component manifest a…
XargonWan May 14, 2026
baa8f0c
feat(satellaview): refactor set_settings to use a single entrypoint […
XargonWan May 14, 2026
94b721c
feat(satellaview): add soundlink streaming during game launch and cle…
XargonWan May 15, 2026
48d425f
fix(satellaview_plus): correct ROM path in error message for missing …
XargonWan May 15, 2026
d3e556a
fix(satellaview_plus): replace rd_zenity with zenity for error handli…
XargonWan May 15, 2026
802e0c4
feat(satellaview): implement soundlink streaming toggle functionality…
XargonWan May 15, 2026
dceed2e
feat(satellaview): refactor launcher script to separate tuner and run…
XargonWan May 15, 2026
4bb830a
feat(satellaview_plus): add new media assets for Satellaview Plus
XargonWan May 15, 2026
3061eec
feat(satellaview): update component launcher to include components.sh…
XargonWan May 15, 2026
e9b5ba3
feat(satellaview): enhance command handling in launcher script with i…
XargonWan May 15, 2026
1c58f67
feat(satellaview): update Soundlink references to Soundlink+ in scrip…
XargonWan May 15, 2026
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
7 changes: 7 additions & 0 deletions automation-tools/alchemist/version_policy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,13 @@ export XENIA_EDGE_VERSION_POLICY="newest"
# ------------------------------------------------------------------------------
export ZESARUX_VERSION_POLICY="latest"

# ------------------------------------------------------------------------------
# Satellaview - Super Famicom Add-on
# ------------------------------------------------------------------------------
export SATELLAVIEW_PLUS_VERSION_POLICY="V5"
export SATELLAVIEW_PLUS_SNES9X_VERSION_POLICY="latest"




# ==============================================================================
Expand Down
1 change: 1 addition & 0 deletions satellaview_plus/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Satellite tuning sound by https://pixabay.com/users/freesound_community-46691455/
4 changes: 4 additions & 0 deletions satellaview_plus/TODO.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
snes9x:
- controller config

what about load/save state?
161 changes: 161 additions & 0 deletions satellaview_plus/component_functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/bin/bash

export satellaview_plus_download_path="$storage_path/satellaview_plus/"
export satellaview_plus_bsx_path="$storage_path/satellaview_plus/roms/bs-x"
export satellaview_plus_config_path="$XDG_CONFIG_HOME/satellaview_plus"
export satellaview_plus_rd_config_dir="$rd_components/satellaview_plus/rd_config"
export satellaview_plus_esde_assets_dir="$rd_components/satellaview_plus/es-de"
export satellaview_plus_config_file="$satellaview_plus_config_path/config.json"
export satellaview_plus_snes9x_config="$XDG_CONFIG_HOME/satellaview_plus/snes9x/snes9x/snes9x.conf"
export satellaview_soundlink_stream="https://howlingf-gecko.radioca.st/stream"

_set_setting_value::satellaview_plus() {

local file="$1"

if [[ "$file" =~ \.json$ ]]; then

local name="$2" value="$3"

local tmp_file
tmp_file="$(mktemp)"

jq --arg name "$name" --arg value "$value" '.[$name] = $value' "$file" > "$tmp_file" && mv -f "$tmp_file" "$file"

elif [[ "$file" =~ \.conf$ ]]; then

local name=$(sed_escape_pattern "$2") value=$(sed_escape_replacement "$3") section="${4:-}"

if [[ -n "$section" ]]; then
section=$(sed_escape_pattern "$section")
sed -i '\^\['"$section"'\]^,\^\^'"$name"'[[:space:]]*=^s^\^'"$name"'[[:space:]]*=.*^'"$name"' = '"$value"'^' "$file"
else
sed -i 's^\^'"$name"'[[:space:]]*=.*^'"$name"' = '"$value"'^' "$file"
fi

fi

}

_get_setting_value::satellaview_plus() {
local file="$1" name="$2" section="${3:-}"

if [[ "$file" =~ \.json$ ]]; then

if [[ -z "$section" ]]; then
jq -r --arg name "$name" '.[$name] // empty' "$file"
elif jq -e --arg section "$section" '.presets | has($section)' "$file" > /dev/null 2>&1; then
jq -r --arg section "$section" --arg name "$name" \
'.presets[$section] | .. | objects | select(has($name)) | .[$name] // empty' "$file"
else
local section_parts section_json
IFS='.' read -ra section_parts <<< "$section"
section_json=$(printf '%s\n' "${section_parts[@]}" | jq -R . | jq -sc .)
jq -r --argjson path "$section_json" --arg name "$name" \
'getpath($path + [$name]) // empty' "$file"
fi

elif [[ "$file" =~ \.conf$ ]]; then

if [[ -n "$section" ]]; then
KEY="$name" SECTION="[$section]" awk -F'=' \
'NR==1 { sub(/^\xEF\xBB\xBF/, "") }
BEGIN { key=ENVIRON["KEY"]; section=ENVIRON["SECTION"] }
$0 == section { in_section=1; next }
/^\[/ { in_section=0 }
in_section && $0 ~ "^" key "[[:space:]]*=" {
gsub(/^[[:space:]]*/, "", $2)
print $2; exit
}' "$file"
else
KEY="$name" awk -F'=' \
'NR==1 { sub(/^\xEF\xBB\xBF/, "") }
BEGIN { key=ENVIRON["KEY"] }
$0 ~ "^" key "[[:space:]]*=" {
gsub(/^[[:space:]]*/, "", $2)
print $2; exit
}' "$file"
fi

fi
}

_prepare_component::satellaview_plus() {
local action="$1"
shift

local component_path="$(get_own_component_path)"

case "$action" in

reset)
log i "-----------------------"
log i "Resetting Satellaview+"
log i "-----------------------"

log i "Clearing BS-X satellite data directory"
create_dir -d "$satellaview_plus_download_path"

log i "Clearing BS-X ROM directory"
create_dir -d "$satellaview_plus_bsx_path"

log i "Initializing Satellaview+ Launcher configuration"
create_dir -d "$satellaview_plus_config_path"
cp -fv "$satellaview_plus_rd_config_dir/config.json" "$satellaview_plus_config_file"
set_setting_value "$satellaview_plus_config_file" "DownloadLocation" "$satellaview_plus_download_path" "satellaview_plus"

log i "Initializing Snes9x configuration for Satellaview+"
create_dir -d "$(dirname "$satellaview_plus_snes9x_config")"
cp -fv "$satellaview_plus_rd_config_dir/snes9x.conf" "$satellaview_plus_snes9x_config"
set_setting_value "$satellaview_plus_snes9x_config" "SRAMDirectory" "$saves_path/satellaview_plus" "satellaview_plus" "Files"
set_setting_value "$satellaview_plus_snes9x_config" "SaveStateDirectory" "$states_path/satellaview_plus" "satellaview_plus" "Files"

log i "Creating ROMs directory and copying launchers"
create_dir "$roms_path/satellaview_plus"
cp -rfv "$satellaview_plus_esde_assets_dir/launchers/"* "$roms_path/satellaview_plus/"

log i "Populating gamelist.xml for ES-DE"
local source_gamelist="$component_path/es-de/gamelist/gamelist.xml"
local dest_gamelist="$rd_home_path/ES-DE/gamelists/satellaview_plus/gamelist.xml"
create_dir "$(dirname "$dest_gamelist")"

log i "Populating ES-DE media assets"
create_dir "$rd_home_path/ES-DE/downloaded_media/satellaview_plus"
cp -rfv "$satellaview_plus_esde_assets_dir/downloaded_media/satellaview_plus/"* "$rd_home_path/ES-DE/downloaded_media/satellaview_plus/"
;;

esac
}

satellaview_toggle_soundlink(){

if [[ "$(get_component_option satellaview_plus satellaview_plus_soundlink_stream_toggle)" == "true" ]]; then
local status="enabled"
else
local status="disabled"
fi

zenity --question --no-wrap \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK: Satellaview+ - Toggle Soundlink+ Stream" \
--text="Soundlink+ stream is currently $status.\n\nDo you want to toggle it?"

# If not cancel
if [[ $? -eq 0 ]]; then

if [[ "$(get_component_option satellaview_plus satellaview_plus_soundlink_stream_toggle)" == "true" ]]; then
set_component_option "satellaview_plus" "satellaview_plus_soundlink_stream_toggle" "false" && log i "Soundlink+ stream disabled"
zenity --info --no-wrap \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK: Satellaview+ - Soundlink+ Stream" \
--text="Soundlink+ stream is now disabled.\n\nYou should start hearing the music within a few seconds after launching a game.\n\nMake sure to have your audio output set up correctly and enjoy the authentic Satellaview+ experience!"
else
set_component_option "satellaview_plus" "satellaview_plus_soundlink_stream_toggle" "true" && log i "Soundlink+ stream enabled"
zenity --info --no-wrap \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK: Satellaview+ - Soundlink+ Stream" \
--text="Soundlink+ stream is now enabled.\n\nYou will no longer hear the music from the Soundlink+ stream when launching a game."
fi

fi
}
114 changes: 114 additions & 0 deletions satellaview_plus/component_launcher.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/bin/bash

source /app/libexec/launcher_functions.sh
source /app/libexec/components.sh

if [[ ! -f "$roms_path/satellaview_plus/bs-x.sfc" ]]; then
zenity --error --no-wrap \
--window-icon="/app/share/icons/hicolor/scalable/apps/net.retrodeck.retrodeck.svg" \
--title "RetroDECK: Satellaview+ - Error: ROM not found" \
--text="Satellaview+ ROM not found.\n\nPlease provide the 'bs-x.sfc' ROM file in the\n\n'$roms_path/satellaview_plus'\n\ndirectory and try again.\n\nNote: you would need either an \"English + No DRM\" or \"Japanese + No DRM\" version to work with Satellaview+.\nRun the BIOS Checker Tool in the Configurator for more information about the required ROMs and their checksums."
exit 1
else
cp "$roms_path/satellaview_plus/bs-x.sfc" "$satellaview_plus_bsx_path/bs-x.sfc"
# TODO: if we need to patch the roms we can do it here
fi

# Setting component name and path based on the directory name
component_name="$(basename "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")"
component_path="$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd)"

log i "RetroDECK is now launching $component_name"
log d "Library path is: $LD_LIBRARY_PATH"

satellaview_tuner() {

export LD_LIBRARY_PATH="$component_path/usr/lib/:$component_path/lib:$rd_shared_libs:${DEFAULT_LD_LIBRARY_PATH}"
export QT_PLUGIN_PATH="${QT_PLUGIN_PATH}"
export QT_QPA_PLATFORM_PLUGIN_PATH="${QT_QPA_PLATFORM_PLUGIN_PATH}"

log i "Opening Satellaview+ Tuner command"

# We move here because the config file is read from ./
cd "$satellaview_plus_config_path"
exec "$component_path/AppRun"

}

run_satellaview(){

export satellaview_plus_download_path="$storage_path/satellaview_plus/"
export satellaview_plus_bsx_path="$storage_path/satellaview_plus/roms/bs-x"

log i "Running Satellaview+ SNES9X"

cd "$storage_path/satellaview_plus/"

# WORKAROUND: the launcher is supposed to move the doiwnloaded satdata into the rom folder (in storage) but is not doing it,
# so we are symlinking it by ourselves before launching the game and cleaning it up later
ln -s "$satellaview_plus_download_path/satdata/"* "$satellaview_plus_bsx_path/"

if [ "$(get_component_option satellaview_plus satellaview_plus_soundlink_stream_toggle)" == "true" ]; then

log i "Soundlink+ stream toggle is enabled, starting the stream"

# Start soundlink+ streaming in the background
ffplay -nodisp -autoexit "$satellaview_soundlink_stream" >/dev/null 2>&1 &
STREAM_PID=$!

# Auto cleanup the stream when the game is closed
cleanup() {
kill "$STREAM_PID" 2>/dev/null
}

trap cleanup EXIT INT TERM

else
log i "Soundlink+ stream toggle is disabled, skipping the stream"
fi

XDG_CONFIG_HOME="$XDG_CONFIG_HOME/satellaview_plus/snes9x" "$component_path/bin/snes9x-gtk" "$satellaview_plus_bsx_path/bs-x.sfc"

# Cleanup the symlinks after the game is closed
log d "Cleaning up symlinks in BS-X ROM directory"
find "$satellaview_plus_bsx_path" -type l -delete

}

# This function is called by the .sh launchers in the rom folder and it decides which command to run based on the content of the launcher script
if [[ -f "$1" ]]; then
log i "Reading command from file '$1'"
command=$(cat "$1")
log i "Command read from file '$1': $command"
elif [[ -n "$1" ]]; then
log i "\"$1\" appears to be a command argument. Using the argument as command."
command="$1"
else
log w "Command file '$1' not found, falling back to default run command"
command="run"
fi

case $command in

tuner|--tuner|-t)
satellaview_tuner
;;

run|--run|-r)
run_satellaview
;;

help|--help|-h)
log i "Available commands in the launcher script:"
log i " tuner, --tuner, -t: Launch the Satellaview+ Tuner"
log i " run, --run, -r: Run the Satellaview+ SNES9X emulator"
log i " help, --help, -h: Show this help message"
;;

*)
log e "Unknown command '$command' in launcher script '$1'"
log w "Falling back to Satellaview+ run command"
run_satellaview
;;

esac
Loading