PaulStretch on Apple Silicon in 2022

It’s become something of a tradition – will the PaulStretch code still work n years later? The answer invariably is, yes!

Clone from github:

% git clone https://github.com/paulnasca/paulstretch_cpp.git
Cloning into 'paulstretch_cpp'…
remote: Enumerating objects: 166, done.
remote: Total 166 (delta 0), reused 0 (delta 0), pack-reused 166
Receiving objects: 100% (166/166), 92.98 KiB | 2.58 MiB/s, done.
Resolving deltas: 100% (101/101), done.

Look at previous notes and install dependencies:

% sudo port install fltk
% sudo port install audiofile
% sudo port install libmad
% sudo port install portaudio
% sudo port install fftw-3-single
% sudo port install mxml

Apply the following patch to XMLwrapper.cpp

% git diff XMLwrapper.cpp
diff --git a/XMLwrapper.cpp b/XMLwrapper.cpp
index 1efb66e..8fe17ad 100644
--- a/XMLwrapper.cpp
+++ b/XMLwrapper.cpp
@@ -29,7 +29,7 @@ int xml_k=0;
 char tabs[STACKSIZE+2];
 
 const char *XMLwrapper_whitespace_callback(mxml_node_t *node,int where){
-    const char *name=node->value.element.name;
+    const char *name=mxmlGetElement(node);
 
     if ((where==MXML_WS_BEFORE_OPEN)&&(!strcmp(name,"?xml"))) return(NULL);
     if ((where==MXML_WS_BEFORE_CLOSE)&&(!strcmp(name,"string"))) return(NULL);
@@ -407,10 +407,10 @@ void XMLwrapper::getparstr(const char *name,char *par,int maxstrlen){
     node=mxmlFindElement(peek(),peek(),"string","name",name,MXML_DESCEND_FIRST);
     
     if (node==NULL) return;
-    if (node->child==NULL) return;
-    if (node->child->type!=MXML_OPAQUE) return;
+    if (mxmlGetFirstChild(node)==NULL) return;
+    if (mxmlGetType(mxmlGetFirstChild(node))!=MXML_OPAQUE) return;
     
-    snprintf(par,maxstrlen,"%s",node->child->value.element.name);
+    snprintf(par,maxstrlen,"%s",mxmlGetText(mxmlGetFirstChild(node), NULL));
     
 };

Generate the UI:

% fluid -c GUI.fl
% fluid -c FreeEditUI.fl

And compile:

% g++ -ggdb -Wno-return-type GUI.cxx FreeEditUI.cxx *.cpp Input/*.cpp Output/*.cpp `fltk-config --cflags` \
 `fltk-config --ldflags`  -laudiofile -lfftw3f -lz -logg -lvorbis -lvorbisenc -lvorbisfile -lportaudio -lpthread -lmad -lmxml -o paulstretch
GUI.cxx:661:23: warning: object backing the pointer will be destroyed at the end of the full-expression [-Wdangling-gsl]
        const char *outstr=control.Render(control.get_input_filename(),outfilename,type,intype,
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.

Ignore the warning and run the thing!

% ./paulstretch &

Building PaulStretch on Mojave in 2019

It’s a weakness. Software archeology. The topic of PaulStretch came up during the week, and of course i wanted to play with it again.

Back in 2013 there were downloadable binaries, but it seems they probably stopped working a few macOS releases ago. And besides, where is the fun in that!

The good news is that despite not being touched for years the code does actually compile.   There is no bad news, it’s working perfectly, and i’m listening to the Alien Sex Fiend track ‘I Walk The Line’ stretched out to 35mins.

After cloning the code from GitHub, it’s just a matter of installing the right libraries. I’m using MacPorts and the other dependency that was missing was mini-xml. That is also on GitHub, but the latest release isn’t compatible, fortunately the v2.12 release is fine.

Work from the script here:

https://github.com/paulnasca/paulstretch_cpp/blob/master/compile_linux_fftw.sh

  • install FLTK (available in MacPorts)
  • run the two fluid commands
  • run the g++ command (changing $outfile to paulstretch
  • install the missing libraries until you get a binary

The missing libraries were:

  • audiofile
  • libmad
  • portaudio
  • fftw-3-single (this is suggested as optional, but it wasn’t hard to include)
  • mini-xml

To install mini-xml it was the usual:

./configure –prefix=/opt/local ; make ; sudo make install

Everything else was just:

sudo port install

Screenshot 2019-03-23 at 17.26.21.png

Aint it pretty!

$ fluid -c GUI.fl
$ fluid -c FreeEditUI.fl

$ g++ -ggdb GUI.cxx FreeEditUI.cxx *.cpp Input/*.cpp Output/*.cpp `fltk-config –cflags“fltk-config –ldflags`-laudiofile -lfftw3f -lz -logg -lvorbis -lvorbisenc -lvorbisfile -lportaudio -lpthread -lmad -lmxml -o paulstretch

FTW, i tried to statically link it but it start to complain about missing libraries. Perhaps i’ll be motivated to learn how to package a .dmg file if there is interest. Surely it can’t be that difficult… right?

Update: it doesn’t look that difficult to create a ‘PaulStretch.app’, there is some Info.plist to create, copy all the libraries into the directory structure:

$ otool -L paulstretch
paulstretch:
/opt/local/lib/libfltk.1.3.dylib
/usr/lib/libSystem.B.dylib
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
/opt/local/lib/libaudiofile.1.dylib
/opt/local/lib/libfftw3f.3.dylib
/opt/local/lib/libz.1.dylib
/opt/local/lib/libogg.0.dylib
/opt/local/lib/libvorbis.0.dylib
/opt/local/lib/libvorbisenc.2.dylib
/opt/local/lib/libvorbisfile.3.dylib
/opt/local/lib/libportaudio.2.dylib
/opt/local/lib/libmad.0.dylib
/opt/local/lib/libmxml.dylib
/usr/lib/libc++.1.dylib

and then update the paths with ‘install_name_tool -change’ to update the paths to reference the copy in the App directory structure.

Check back tomorrow!

Update: after a few more shenanigans fixing library references in libraries that reference libraries (it’s turtles all the way down, etc) there is now a “nicely” packaged ‘PaulStretch.app’ that can be distributed in a DMG image. It has even been tested off my machine!

$ tree PaulStretch.app
PaulStretch.app
└── Contents
    ├── Info.plist
    ├── MacOS
    │   ├── libFLAC.8.dylib
    │   ├── libaudiofile.1.dylib
    │   ├── libfftw3f.3.dylib
    │   ├── libfltk.1.3.dylib
    │   ├── libmad.0.dylib
    │   ├── libmxml.dylib
    │   ├── libogg.0.dylib
    │   ├── libportaudio.2.dylib
    │   ├── libvorbis.0.dylib
    │   ├── libvorbisenc.2.dylib
    │   ├── libvorbisfile.3.dylib
    │   ├── libz.1.dylib
    │   └── paulstretch
    └── Resources
        └── PaulStretch.icns