#! /bin/bash -e

#########################################################################################
#                                                                                       #
#  Compiles Faust programs to OSX/iOS libraries suitable for the Unity environment      #
#                             (c) Grame, 2017-2024                                      #
#                                                                                       #
#                                                                                       #
#########################################################################################


#   This script shouldn't be used on its own, use the "faust2unity" script instead
#   The libraries are firstly wrapped by the unityplugin.cpp architecture file
#   They have to be used in the Unity environment
#   The libraries does not work by themselves, they need the FaustPlugin_<dspname>.cs and FaustUtilities_<dspname>.cs files to be functional
#   These files are automatically generated by the "faust2unity" script
#
#
#   Structure of a plugin for OSX
#-----------------------------------------
#   libFaustPlugin_foo.bundle/
#       Contents/
#           MacOS/
#               AudioPlugin<dspname>
#           Info.plist
#

. faustpath
. faustoptflags
. usage.sh

CXXFLAGS+=" $MYGCCFLAGS"  # So that additional CXXFLAGS can be used

NVOICES=-1

#------------------------------------------------
# Compiler settings
ARCH="-arch x86_64"
CXXFLAGS+=" -fPIC"
LDFLAGS="-bundle"
CXX="c++"

#------------------------------------------------
# Generates the info.plist file

createInfoPList() {
cat > "$2" << DELIM
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>BuildMachineOSBuild</key>
    <string>16D32</string>
    <key>CFBundleDevelopmentRegion</key>
    <string>English</string>
    <key>CFBundleExecutable</key>
    <string>$1</string>
    <key>CFBundleIdentifier</key>
    <string>com.yourcompany.$1</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>$1</string>
    <key>CFBundlePackageType</key>
    <string>BNDL</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0</string>
    <key>CFBundleSignature</key>
    <string>????</string>
    <key>CFBundleSupportedPlatforms</key>
    <array>
        <string>MacOSX</string>
    </array>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>CFPlugInDynamicRegisterFunction</key>
    <string></string>
    <key>CFPlugInDynamicRegistration</key>
    <string>NO</string>
    <key>CFPlugInFactories</key>
    <dict>
        <key>00000000-0000-0000-0000-000000000000</key>
        <string>MyFactoryFunction</string>
    </dict>
    <key>CFPlugInTypes</key>
    <dict>
        <key>00000000-0000-0000-0000-000000000000</key>
        <array>
            <string>00000000-0000-0000-0000-000000000000</string>
        </array>
    </dict>
    <key>CFPlugInUnloadFunction</key>
    <string></string>
    <key>DTCompiler</key>
    <string>com.apple.compilers.llvm.clang.1_0</string>
    <key>DTPlatformBuild</key>
    <string>8C1002</string>
    <key>DTPlatformVersion</key>
    <string>GM</string>
    <key>DTSDKBuild</key>
    <string>16C58</string>
    <key>DTSDKName</key>
    <string>macosx10.12</string>
    <key>DTXcode</key>
    <string>0821</string>
    <key>DTXcodeBuild</key>
    <string>8C1002</string>
</dict>
</plist>
DELIM
}

echoHelp()
{
    usage faust2osxiosunity "[options] [Faust options] <file.dsp>"
    platform MacOSX
    require Unity
    echo "Compiles Faust programs to OSX/iOS libraries suitable for the Unity environment"
    option
    option "-nvoices <num>"
    option -ios "creates an iOS static library"
    option -universal "generates an universal (arm/intel) external on OSX"
    option "Faust options"
    # echo "Use 'faust2unity -osx -ios' to also create the c# and JSON files"
    echo "See architecture/unity/README.md for more info."
    exit
}

if [ "$#" -eq 0 ]; then
    echo 'Please, provide a Faust file to process !'
    echo ''
    echoHelp
fi

#---------------------------------------
# Dispatch command arguments

CUR=$(pwd)
SOURCE=0

while [ $1 ]
do
    p=$1

    if [ $p = "-help" ] || [ $p = "-h" ]; then
        echoHelp
    elif [ $p = "-ios" ]; then
        IOS=1
        CXXFLAGS="-arch armv7 -arch armv7s -arch arm64 -pipe -O3 -gdwarf-2"
    elif [ $p = "-nvoices" ]; then
        shift
        NVOICES=$1
    elif [ $p = "-source" ]; then
        SOURCE=1
    elif [ $p = "-universal" ]; then
        ARCH="-arch arm64 -arch x86_64"
    elif [ ${p:0:1} = "-" ]; then
        OPTIONS="$OPTIONS $p"
    elif [[ -f "$p" ]] && [ ${p: -4} == ".dsp" ]; then
        FILES="$FILES $p"
    else
        OPTIONS="$OPTIONS $p"
    fi

shift
done

#--------------------------------------
# Compiles all *.dsp files

for p in $FILES; do
    CUR=$(pwd)
    f=$(basename "$p")
    NAME=${f%.dsp}
    FNAME=FaustPlugin_$NAME
    SRCDIR=$(dirname "$p")

    if [ "$IOS" = "1" ]; then # iOS part

        FIN=$FNAME/iOS

        # creates a temporary dir
        TMP=$(mktemp -d iOS.XXXX)

        # checks if final dir exists, if not creates it
        if [ ! -d "$FIN" ]; then
            mkdir -p "$FIN"
        fi

        # compiles faust to c++
        faust -uim -i -a $FAUSTARCH/unity/unityplugin.cpp "$SRCDIR/$NAME.dsp" -o $TMP/$NAME.cpp || (echo "$FNAME : Faust to C++ compilation failed in faust2osxiosunity -ios"; exit 1)

        $CXX $CXXFLAGS -DAPPLE -fembed-bitcode -DPLUGINNAME="libFaustPlugin_$NAME" -std=c++11 -stdlib=libc++ -c -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk $TMP/$NAME.cpp -o $TMP/$NAME.o || (echo "$FNAME : C++ to iOS library compilation failed in faust2osxiosunity -ios"; exit 1)
        libtool $TMP/$NAME.o -o $TMP/libFaustPlugin_$NAME.a
        rm $TMP/$NAME.o $TMP/$NAME.cpp

        # moves binary to final
        mv $TMP/* $FIN/
        rm -rf $TMP

        echo "$f : iOS compilation completed"

    else # MacOS part

        FIN=$FNAME/MacOS

        # creates a temporary dir
        TDR=$(mktemp -d faust.XXX)

        # creates the bundle inside
        BNDL="$TDR/lib$FNAME.bundle"
        MOS="$BNDL/Contents/MacOS/"
        mkdir -p "$MOS"

        # checks if final dir exists, if not creates it
        if [ ! -d "$FIN" ]; then
            mkdir -p "$FIN"
        fi

        # compile Faust DSP to c++
        faust -uim -i -a $FAUSTARCH/unity/unityplugin.cpp "$SRCDIR/$NAME.dsp" -o "$MOS/$NAME.cpp" || (echo "$FNAME : Faust to C++ compilation failed in faust2osxiosunity"; exit 1)

        if [ $NVOICES == -1 ]; then
             $CXX $CXXFLAGS $ARCH $LDFLAGS -DAPPLE -DPLUGINNAME="$NAME" "$MOS/$NAME.cpp" -o "$MOS/lib$FNAME" || (echo "$FNAME : C++ to OSX library compilation failed in faust2osxiosunity"; exit 1)
        else
             $CXX $CXXFLAGS $ARCH $LDFLAGS -DPOLY -DAPPLE -DPLUGINNAME="$NAME" "$MOS/$NAME.cpp" -o "$MOS/lib$FNAME" || (echo "$FNAME : C++ to OSX library compilation failed in faust2osxiosunity"; exit 1)
        fi

        rm "$MOS/$NAME.cpp"
        createInfoPList "lib$FNAME" "$BNDL/Contents/Info.plist" || (echo "$FNAME : Info.plist gerenation failed in faust2osxiosunity"; exit 1)

        rm -rf "$SRCDIR/lib$FNAME.bundle"

        # moves binary to final
        mv $BNDL $FIN/
        rm -rf $TDR

        echo "$f : OSX compilation completed"

    fi

done
