1{
2 stdenv,
3 lib,
4 fetchFromGitHub,
5 wrapQtAppsHook,
6 makeDesktopItem,
7 copyDesktopItems,
8 cmake,
9 pkg-config,
10 catch2_3,
11 qtbase,
12 qtsvg,
13 qttools,
14 qtwayland,
15 qwt,
16 qscintilla,
17 kissfftFloat,
18 crossguid,
19 reproc,
20 platform-folders,
21 ruby_3_2,
22 erlang,
23 elixir,
24 beamPackages,
25 alsa-lib,
26 rtmidi,
27 boost,
28 aubio,
29 jack2,
30 jack-example-tools,
31 pipewire,
32 supercollider-with-sc3-plugins,
33 parallel,
34
35 withTauWidget ? false,
36 qtwebengine,
37
38 withImGui ? false,
39 gl3w,
40 SDL2,
41 fmt,
42}:
43
44# Sonic Pi fails to build with Ruby 3.3.
45let
46 ruby = ruby_3_2;
47in
48
49stdenv.mkDerivation rec {
50 pname = "sonic-pi";
51 version = "4.5.1";
52
53 src = fetchFromGitHub {
54 owner = "sonic-pi-net";
55 repo = pname;
56 rev = "v${version}";
57 hash = "sha256-JMextQY0jLShWmqRQoVAbqIzDhA1mOzI7vfsG7+jjX0=";
58 };
59
60 mixFodDeps = beamPackages.fetchMixDeps {
61 inherit version;
62 pname = "mix-deps-${pname}";
63 mixEnv = "test";
64 src = "${src}/app/server/beam/tau";
65 hash = "sha256-7wqFI3f0CRVrXK2IUguqHNANwKMmTak/Xh9nr624TXc=";
66 };
67
68 strictDeps = true;
69
70 nativeBuildInputs = [
71 wrapQtAppsHook
72 copyDesktopItems
73 cmake
74 pkg-config
75 ruby
76 erlang
77 elixir
78 beamPackages.hex
79 ];
80
81 buildInputs = [
82 qtbase
83 qtsvg
84 qttools
85 qtwayland
86 qwt
87 qscintilla
88 kissfftFloat
89 catch2_3
90 crossguid
91 reproc
92 platform-folders
93 ruby
94 alsa-lib
95 rtmidi
96 boost
97 aubio
98 ]
99 ++ lib.optionals withTauWidget [
100 qtwebengine
101 ]
102 ++ lib.optionals withImGui [
103 gl3w
104 SDL2
105 fmt
106 ];
107
108 nativeCheckInputs = [
109 parallel
110 supercollider-with-sc3-plugins
111 jack2
112 ];
113
114 cmakeFlags = [
115 "-DUSE_SYSTEM_LIBS=ON"
116 "-DBUILD_IMGUI_INTERFACE=${if withImGui then "ON" else "OFF"}"
117 "-DWITH_QT_GUI_WEBENGINE=${if withTauWidget then "ON" else "OFF"}"
118 "-DAPP_INSTALL_ROOT=${placeholder "out"}/app"
119 ];
120
121 doCheck = true;
122
123 postPatch = ''
124 # Fix shebangs on files in app and bin scripts
125 patchShebangs app bin
126 '';
127
128 preConfigure = ''
129 # Set build environment
130 export SONIC_PI_HOME="$TMPDIR/spi"
131
132 export HEX_HOME="$TEMPDIR/hex"
133 export HEX_OFFLINE=1
134 export MIX_REBAR3='${beamPackages.rebar3}/bin/rebar3'
135 export REBAR_GLOBAL_CONFIG_DIR="$TEMPDIR/rebar3"
136 export REBAR_CACHE_DIR="$TEMPDIR/rebar3.cache"
137 export MIX_HOME="$TEMPDIR/mix"
138 export MIX_DEPS_PATH="$TEMPDIR/deps"
139 export MIX_ENV=prod
140
141 # Copy Mix dependency sources
142 echo 'Copying ${mixFodDeps} to Mix deps'
143 cp --no-preserve=mode -R '${mixFodDeps}' "$MIX_DEPS_PATH"
144
145 # Change to project base directory
146 cd app
147
148 # Prebuild Ruby vendored dependencies and Qt docs
149 ./linux-prebuild.sh -o
150 '';
151
152 postBuild = ''
153 # Build BEAM server
154 ../linux-post-tau-prod-release.sh -o
155 '';
156
157 checkPhase = ''
158 runHook preCheck
159
160 # BEAM tests
161 pushd ../server/beam/tau
162 MIX_ENV=test TAU_ENV=test mix test
163 popd
164
165 # Ruby tests
166 pushd ../server/ruby
167 rake test
168 popd
169
170 # API tests
171 pushd api-tests
172 # run JACK parallel to tests and quit both when one exits
173 SONIC_PI_ENV=test parallel --no-notice -j2 --halt now,done=1 ::: 'jackd -rd dummy' 'ctest --verbose'
174 popd
175
176 runHook postCheck
177 '';
178
179 installPhase = ''
180 runHook preInstall
181
182 # Run Linux release script
183 ../linux-release.sh
184
185 # Copy dist directory to output
186 mkdir $out
187 cp -r linux_dist/* $out/
188
189 # Copy icon
190 install -Dm644 ../gui/qt/images/icon-smaller.png $out/share/icons/hicolor/256x256/apps/sonic-pi.png
191
192 runHook postInstall
193 '';
194
195 # $out/bin/sonic-pi is a shell script, and wrapQtAppsHook doesn't wrap them.
196 dontWrapQtApps = true;
197 preFixup = ''
198 # Wrap Qt GUI (distributed binary)
199 wrapQtApp $out/bin/sonic-pi \
200 --prefix PATH : ${
201 lib.makeBinPath [
202 ruby
203 supercollider-with-sc3-plugins
204 jack2
205 jack-example-tools
206 pipewire.jack
207 ]
208 }
209
210 # If ImGui was built
211 if [ -e $out/app/build/gui/imgui/sonic-pi-imgui ]; then
212 # Wrap ImGui into bin
213 makeWrapper $out/app/build/gui/imgui/sonic-pi-imgui $out/bin/sonic-pi-imgui \
214 --inherit-argv0 \
215 --prefix PATH : ${
216 lib.makeBinPath [
217 ruby
218 supercollider-with-sc3-plugins
219 jack2
220 jack-example-tools
221 pipewire.jack
222 ]
223 }
224 fi
225
226 # Remove runtime Erlang references
227 for file in $(grep -FrIl '${erlang}/lib/erlang' $out/app/server/beam/tau); do
228 substituteInPlace "$file" --replace '${erlang}/lib/erlang' $out/app/server/beam/tau/_build/prod/rel/tau
229 done
230 '';
231
232 stripDebugList = [
233 "app"
234 "bin"
235 ];
236
237 desktopItems = [
238 (makeDesktopItem {
239 name = "sonic-pi";
240 exec = "sonic-pi";
241 icon = "sonic-pi";
242 desktopName = "Sonic Pi";
243 comment = meta.description;
244 categories = [
245 "Audio"
246 "AudioVideo"
247 "Education"
248 ];
249 })
250 ];
251
252 passthru.updateScript = ./update.sh;
253
254 meta = with lib; {
255 homepage = "https://sonic-pi.net/";
256 description = "Free live coding synth for everyone originally designed to support computing and music lessons within schools";
257 license = licenses.mit;
258 maintainers = with maintainers; [
259 Phlogistique
260 kamilchm
261 c0deaddict
262 sohalt
263 ];
264 platforms = platforms.linux;
265 };
266}