1#!/usr/local/bin/bash
2
3#set -x
4
5. faustpath
6. faustoptflags
7. usage.sh
8
9# Check for some common locations of the VST SDK files. This falls back to
10# /usr/local/src/vstsdk if none of these are found. In that case, or if make
11# picks the wrong location, you can also set the SDK variable explicitly.
12
13#SDK=/usr/local/src/vstsdk
14
15# Note that the paths to be searched are listed in reverse order here, so that
16# the preferred path comes *last*.
17sdkpaths="/usr/src/VST* /usr/src/vst* /usr/include/VST* /usr/include/vst* /opt/local/src/VST* /opt/local/src/vst* /opt/local/include/VST* /opt/local/include/vst* /usr/local/src/VST* /usr/local/src/vst* /usr/local/include/VST* /usr/local/include/vst* $VSTSDK"
18# This should hopefully work on *BSD, Linux and Mac OSX.
19[ -z "$SDK" ] && SDK=$(echo $sdkpaths | xargs ls -f -d 2>/dev/null | tail -n 1)
20[ -z "$SDK" ] && SDK=/usr/local/src/vstsdk
21
22# SDKSRC should point to the SDK source files (vstplugmain.cpp et al).
23# Usually these are either directly under $SDK or in the
24# public.sdk/source/vst2.x subdirectory.
25[ -z "$SDKSRC" -a -f "$SDK/vstplugmain.cpp" ] && SDKSRC="$SDK"
26[ -z "$SDKSRC" -a -f "$SDK/public.sdk/source/vst2.x/vstplugmain.cpp" ] && SDKSRC="$SDK/public.sdk/source/vst2.x"
27[ -z "$SDKSRC" ] && SDKSRC="$SDK/public.sdk/source/vst2.x"
28
29# Default qmake setup (for GUI compilation). This requires Qt4 or Qt5 (Qt5 is
30# preferred). We try to locate the qmake executable in some common locations
31# here. If this doesn't work out then you can also set the QMAKE environment
32# variable explicitly, or use one of the -qt4 and -qt5 options below.
33[ -z "$QMAKE" ] && QMAKE=$(which qmake-qt5 || which /opt/local/libexec/qt5/bin/qmake || which qmake-qt4 || which /opt/local/libexec/qt4/bin/qmake || echo qmake)
34
35# Where the Faust includes live. We assume that this is under the prefix of
36# whatever Faust binary 'which' locates. You can also specify this explicitly
37# by setting the FAUSTINC environment variable accordingly.
38# FAUSTINC is now set by faustpath
39#[ -z "$FAUSTINC" ] && FAUSTINC=$(which faust 2>/dev/null | sed -e 's?/bin/faust?/include/faust?')
40
41# Where our own Faust library files are. This may be under a different prefix
42# or not installed anywhere. We try 'ls' on faustvstqt.h in some common
43# locations here, and fall back to the current directory if the file isn't
44# found, so that you can run the script from the faust-vst source
45# directory. You can also specify this explicitly by setting the FAUSTARCH
46# environment variable accordingly.
47
48# The part below is obsolete
49# architecture location is now defined by faustpath and stored in a variable named FAUSTARCH
50#[ -z "$FAUSTLIB" ] && FAUSTLIB=$(dirname "$((ls -f /usr/share/faust/faustvstqt.h /usr/local/share/faust/faustvstqt.h /opt/local/share/faust/faustvstqt.h "$PWD/faustvstqt.h" 2>/dev/null)|tail -1)")
51#[ -z "$FAUSTLIB" ] && FAUSTLIB="$PWD"
52
53# defaults (these can be changed with the options listed below)
54FAUST_META=1
55FAUST_MIDICC=1
56FAUST_MTS=1
57FAUST_UI=0
58VOICE_CTRLS=1
59NVOICES=-1
60
61KEEP="no"
62STYLE=""
63
64PROCARCH="-fPIC"
65dllext=".so"
66CXXFLAGS="-O3 -std=c++11 -march=native -mfpmath=sse -msse -msse2 -msse3 -ffast-math -ftree-vectorize"
67
68# Darwin-specific
69#ARCH="-arch i386 -arch x86_64"
70if [[ $(uname) == Darwin || $CROSSTARGET == Darwin ]]; then
71    CXXFLAGS="-O3 -std=c++11 $ARCH -mfpmath=sse -msse -msse2 -msse3 -ffast-math -ftree-vectorize -I/opt/local/include"
72    dllext=".vst"
73fi
74
75# dispatch command arguments
76for ((i=1;i<$#+1;i++)); do
77    p=${!i}
78    if [ $p = "-help" ] || [ $p = "-h" ]; then
79    	usage faust2faustvst "[options ...] <file.dsp>"
80		require VST SDK
81		echo  "Compiles Faust programs to VST plugins"
82		option
83		options -osc -httpd
84		option -gui "build the plugin GUI."
85		option -keep "retain the build directory."
86		option -nometa "ignore metadata (author information etc.) from the Faust source"
87		option -nomidicc "plugin doesn't process MIDI control data."
88		option -notuning "disable the tuning control (instruments only)."
89		option -novoicectrls "no extra polyphony/tuning controls on GUI (instruments only)"
90		option "-nvoices N" "number of synth voices (instruments only; arg must be an integer)"
91		option "-qt4, -qt5" "select the GUI toolkit (requires Qt4/5; implies -gui)."
92		option "-style S" "  select the stylesheet (arg must be Default, Blue, Grey or Salmon)."
93		cat <<EOF
94Environment variables:
95  FAUSTINC: specify the location of the Faust include directory
96    Default: $FAUSTINC
97  FAUSTARCH: specify the location of the Faust VST library files
98    Default: $FAUSTARCH
99  QMAKE: specify the location of the qmake binary
100    Default: $QMAKE
101  SDK: specify the location of the VST SDK
102    Default: $SDK
103  SDKSRC: specify the location of the VST SDK sources
104    Default: $SDKSRC
105EOF
106	exit 0
107    elif [ $p = "-omp" ]; then
108	: ignore
109    elif [ $p = "-icc" ]; then
110	CXX=icpc
111	CXXFLAGS="-O3 -std=c++11 -xHost -ftz -fno-alias -fp-model fast=2"
112    elif [ $p = "-osc" ]; then
113	OSCDEFS="DEFINES += OSCCTRL"
114	OSCLIBS="-lOSCFaust"
115    elif [ $p = "-httpd" ]; then
116	HTTPDEFS="DEFINES += HTTPCTRL"
117	HTTPLIBS="-lHTTPDFaust -lmicrohttpd"
118    elif [ $p = "-qrcode" ]; then # requires -httpd
119	QRDEFS="DEFINES += QRCODECTRL"
120    elif [ $p = "-nometa" ]; then
121	FAUST_META=0
122    elif [ $p = "-nomidicc" ]; then
123	FAUST_MIDICC=0
124    elif [ $p = "-notuning" ]; then
125	FAUST_MTS=0
126    elif [ $p = "-novoicectrls" ]; then
127	VOICE_CTRLS=0
128    elif [ $p = "-gui" ]; then
129	FAUST_UI=1
130	plugin_gui=yes
131    elif [ $p = "-qt4" ]; then
132	FAUST_UI=1
133	plugin_gui=yes
134	QMAKE=$(which qmake-qt4 || which /opt/local/libexec/qt4/bin/qmake || echo qmake-qt4)
135    elif [ $p = "-qt5" ]; then
136	FAUST_UI=1
137	plugin_gui=yes
138	QMAKE=$(which qmake-qt5 || which /opt/local/libexec/qt5/bin/qmake || echo qmake-qt5)
139    elif [ $p = "-nvoices" ]; then
140	(( i++ ))
141	NVOICES=${!i}
142    elif [ $p = "-arch32" ]; then
143	PROCARCH="-m32 -L/usr/lib32"
144    elif [ $p = "-arch64" ]; then
145	PROCARCH="-m64 -fPIC"
146    elif [ $p = "-osx" ]; then
147	CXXFLAGS="-O3 -std=c++11 $ARCH -mfpmath=sse -msse -msse2 -msse3 -ffast-math -ftree-vectorize -I/opt/local/include"
148	dllext=".vst"
149    elif [ $p = "-keep" ]; then
150	KEEP="yes"
151    elif [ $p = "-style" ]; then
152	(( i++ ))
153	STYLE=${!i}
154    elif [ ${p:0:1} = "-" ]; then
155	OPTIONS="$OPTIONS $p"
156    elif [[ -f "$p" ]] && [ ${p: -4} == ".dsp" ]; then
157	FILES="$FILES $p"
158    else
159	OPTIONS="$OPTIONS $p"
160    fi
161done
162
163FILES=( $FILES )
164if [ ${#FILES[@]} = 0 ]; then
165    echo "$0: no filename specified" >&2
166    exit 1
167elif [ ${#FILES[@]} -gt 1 ]; then
168    echo "$0: multiple filenames specified" >&2
169    exit 1
170fi
171
172# Check to see whether the required include and library files are where we
173# expect them, and bail out with an error message otherwise.
174if [ ! -f "$FAUSTINC/faust/gui/QTUI.h" ]; then echo "$0: faust include files not found" >&2; exit 1; fi
175if [ ! -f "$FAUSTARCH/faustvstqt.h" ]; then echo "$0: faust-vst library files not found" >&2; exit 1; fi
176
177# Determine the Qt version so that we can pick the needed compilation options.
178QTVERSION=$($QMAKE -v 2>/dev/null | tail -1 | sed 's/.*Qt version \([0-9]\).*/\1/')
179
180QTEXTRA=
181if [ $QTVERSION = 5 ]; then
182QTEXTRA=x11extras
183fi
184
185arch=faustvst.cpp
186dspname=${FILES[0]}
187SRCDIR=$(dirname "$dspname")
188ABSDIR=$(cd $SRCDIR && pwd)
189CURDIR=$(pwd)
190
191clsname=`basename "$dspname" .dsp`
192cppname="$clsname.cpp"
193soname="$clsname$dllext"
194tmpdir=`mktemp -d /tmp/faust2faustvst.XXXXXX`
195
196RESOURCES=
197STYLE_CXXFLAGS=
198if [ -n "$STYLE" ]; then
199    RESOURCES="RESOURCES+=$FAUSTINC/faust/gui/Styles/$STYLE.qrc"
200    STYLE_CXXFLAGS="QMAKE_CXXFLAGS+=-DSTYLE=\"$STYLE\""
201fi
202
203# now set in faustoptflags
204#CXX=g++
205CPPFLAGS="-DFAUST_META=$FAUST_META -DFAUST_MIDICC=$FAUST_MIDICC -DFAUST_MTS=$FAUST_MTS -DFAUST_UI=$FAUST_UI -DVOICE_CTRLS=$VOICE_CTRLS -I$SDK -I$SDKSRC -D__cdecl="
206if [ $NVOICES -ge 0 ]; then
207CPPFLAGS="$CPPFLAGS -DNVOICES=$NVOICES"
208fi
209
210# Extra SDK modules needed to build a working plugin.
211main=vstplugmain.cpp
212afx=audioeffect.cpp
213afxx=audioeffectx.cpp
214sdksrc="$SDKSRC/$main $SDKSRC/$afx $SDKSRC/$afxx"
215
216# Uncomment this to have Faust substitute the proper class name into the C++
217# code. NOTE: This requires that the basename of the dsp file is a valid C
218# identifier, which isn't guaranteed, so we disable this by default.
219#OPTIONS="$OPTIONS -cn \"$clsname\""
220
221# Create the temp directory.
222mkdir -p $tmpdir
223#trap "echo $0: compile error, intermediate files left in $tmpdir >&2" EXIT
224# Compile the Faust module.
225faust -i -a "$FAUSTARCH/$arch" $OPTIONS "$dspname" -o "$tmpdir/$cppname" || exit 1
226if [ -n "$plugin_gui" ]; then
227# We have to use qmake here.
228# XXXTODO: OSX support
229(
230    cd "$tmpdir"
231    $QMAKE -project -t lib -o ${clsname}.pro "CONFIG += gui plugin no_plugin_name_prefix warn_off" "QT += widgets printsupport network $QTEXTRA" "INCLUDEPATH+=$ABSDIR" "INCLUDEPATH+=$CURDIR" "INCLUDEPATH+=$FAUSTARCH" "INCLUDEPATH+=$FAUSTINC" "QMAKE_CXXFLAGS=-std=c++11 $CPPFLAGS" $STYLE_CXXFLAGS "LIBS+=$ARCHLIB $OSCLIBS $HTTPLIBS" "SOURCES+=$SDKSRC/$main $SDKSRC/$afx $SDKSRC/$afxx" "HEADERS+=$FAUSTARCH/faustvstqt.h $FAUSTINC/faust/gui/QTUI.h" $RESOURCES "$OSCDEFS" "$HTTPDEFS" "$QRDEFS"
232    $QMAKE *.pro
233    make
234) > /dev/null || exit 1
235else
236if [[ $(uname) == Darwin || $CROSSTARGET == Darwin ]]; then
237    mkdir -p $tmpdir/$soname/Contents/MacOS
238    printf '%s' 'BNDL????' > $tmpdir/$soname/Contents/PkgInfo
239    sed -e "s?@name@?$clsname?g;s?@version@?1.0.0?g" > $tmpdir/$soname/Contents/Info.plist <<EOF
240<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
241<plist version="1.0">
242<dict>
243	<key>CFBundleDevelopmentRegion</key>
244	<string>English</string>
245	<key>CFBundleExecutable</key>
246	<string>@name@</string>
247	<key>CFBundleIdentifier</key>
248	<string>@name@</string>
249	<key>CFBundleInfoDictionaryVersion</key>
250	<string>6.0</string>
251	<key>CFBundleName</key>
252	<string>@name@</string>
253	<key>CFBundlePackageType</key>
254	<string>BNDL</string>
255	<key>CFBundleShortVersionString</key>
256	<string>@version@</string>
257	<key>CFBundleSignature</key>
258	<string>????</string>
259	<key>CFBundleVersion</key>
260	<string>@version@</string>
261	<key>CSResourcesFileMapped</key>
262	<true/>
263</dict>
264</plist>
265EOF
266    $CXX -bundle $CXXFLAGS $FAUSTTOOLSFLAGS $PROCARCH -I"$ABSDIR" $CPPFLAGS $sdksrc "$tmpdir/$cppname" -o "$tmpdir/$soname/Contents/MacOS/$clsname" || exit 1
267else
268    $CXX -shared $CXXFLAGS $FAUSTTOOLSFLAGS $PROCARCH -I"$ABSDIR" $CPPFLAGS $sdksrc "$tmpdir/$cppname" -o "$tmpdir/$soname" || exit 1
269fi
270fi
271#trap - EXIT
272
273# copy down the plugin (bundle on OS X)
274rm -rf "$SRCDIR/$soname"
275cp -r "$tmpdir/$soname" "$SRCDIR"
276if [[ $KEEP == yes ]]; then
277    # keep the build directory
278    rm -rf "$SRCDIR/$clsname"
279    mv $tmpdir "$SRCDIR/$clsname"
280else
281    # Clean up.
282    rm -rf $tmpdir
283fi
284# Print the name of the generated plugin.
285echo "$SRCDIR/$soname;"
286