fabiangreffrath / woof

Woof! is a continuation of the Boom/MBF bloodline of Doom source ports.
GNU General Public License v2.0
202 stars 32 forks source link

Suggestion: Allow soundfonts to be loaded from ~/.local/share/woof/soundfonts on Linux #1781

Closed JustinWayland closed 1 month ago

JustinWayland commented 1 month ago

I've been experimenting with Woof! on Linux, and so far it's been pretty good and surprisingly performant for a software renderer. However, adding my own soundfonts has been a noticeable pain point. To install an SC-55 soundfont I had, I had to install it to /usr/share/soundfonts, which has one issue: Linux requires superuser permissions to access the folder. This made installation super annoying.

~/.local/share/woof/soundfonts would be a far less annoying location to install to, since I would be able to put soundfonts in there without needing to use the sudo command and enter my password.

Feel free to close this if this is a limitation of the AppImage format.

fabiangreffrath commented 1 month ago

I'd prefer if soundfonts could get loaded from a user directory that is not specific to Woof. The most obvious solution in this case would be to replace the /usr/share parts in the global search directories with the user's ~/.local/share.

The following patch implements this:

--- a/src/i_flmusic.c
+++ b/src/i_flmusic.c
@@ -38,6 +38,7 @@ typedef fluid_long_long_t fluid_int_t;
 #include "i_printf.h"
 #include "i_sound.h"
 #include "m_array.h"
+#include "m_io.h"
 #include "m_misc.h"
 #include "memio.h"
 #include "mus2mid.h"
@@ -100,9 +101,36 @@ static fluid_long_long_t FL_sftell(void *handle)

 static void ScanDir(const char *dir)
 {
+    const char usr_share[] = "/usr/share";
     char *rel = NULL;
     glob_t *glob;

+    // [FG] replace global "/usr/share" with user's "~/.local/share"
+    if (strncmp(dir, usr_share, strlen(usr_share)) == 0)
+    {
+        char *home_dir = M_getenv("XDG_DATA_HOME");
+
+        if (home_dir == NULL)
+        {
+            home_dir = M_getenv("HOME");
+        }
+
+        if (home_dir)
+        {
+            char *local_share = M_StringJoin(home_dir, "/.local/share");
+            char *local_dir = M_StringReplace(dir, usr_share, local_share);
+
+            // [FG] do not trigger this code path again
+            if (strncmp(local_dir, usr_share, strlen(usr_share)) != 0)
+            {
+                ScanDir(local_dir);
+            }
+
+            free(local_dir);
+            free(local_share);
+        }
+    }
+
     // [FG] relative to the executable directory
     if (dir[0] == '.')
     {