# vim: filetype=python expandtab sw=4 tabstop=4

import sys
import glob

Import("commonEnvironment", "commandOptions", "util" )
Import("configure")

commandOptions.Add('buildImageOpcodes',
    'Set to 0 to avoid building image opcodes',
    '1')
commandOptions.Add('useOSC',
    'Set to 1 if you want OSC support',
    '0')
if util.platform != 'win32':
    commandOptions.Add('useUDP',
        'Set to 0 if you do not want UDP support',
        '1')
else:
    commandOptions.Add('useUDP',
        'Set to 1 if you want UDP support',
        '0')
commandOptions.Add('buildFluidOpcodes',
    'Set to 1 to build the Fluid Opcodes',
    '0')
commandOptions.Add('buildDSSI',
    "Build DSSI/LADSPA host opcodes",
    '0')
commandOptions.Add('buildLoris',
    'Set to 1 to build the Loris Python extension and opcodes',
    '0')

commandOptions.Update(commonEnvironment)
Help(commandOptions.GenerateHelpText(commonEnvironment))

util.fixEnvForOLPC(commonEnvironment)

pluginEnvironment = commonEnvironment.Clone()

buildOLPC = (commonEnvironment['buildOLPC'] != '0')

if util.platform == 'darwin':
    pluginEnvironment.Append(LINKFLAGS = Split('''
        -framework CoreMidi -framework CoreFoundation -framework CoreAudio
    '''))
    # pluginEnvironment.Append(LINKFLAGS = ['-dynamiclib'])
    pluginEnvironment['SHLIBSUFFIX'] = '.dylib'
    pluginEnvironment.Prepend(CXXFLAGS = "-fno-rtti")

stdsrcs = Split( '''
                    bbcut.c         biquad.c
    butter.c        clfilt.c        cross2.c
    dam.c           dcblockr.c      filter.c
    flanger.c       follow.c        fout.c
    freeverb.c      ftconv.c        ftgen.c
    gab/gab.c       gab/vectorial.c grain.c
    locsig.c        lowpassr.c      metro.c
    midiops2.c      midiops3.c      newfils.c
    nlfilt.c        oscbnk.c        pluck.c
    repluck.c       reverbsc.c      seqtime.c
    sndloop.c       sndwarp.c       space.c
                    syncgrain.c     ugens7.c
    ugens9.c        ugensa.c        uggab.c
    ugmoss.c                        ugsc.c
    wave-terrain.c  stdopcod.c
        ''')
if not buildOLPC:
    stdsrcs.append(Split('ambicode.c spat3d.c ugnorman.c') )

util.makePlugin(pluginEnvironment, 'stdopcod', stdsrcs)

if util.platform != 'win32' and not buildOLPC:
    util.makePlugin(pluginEnvironment, 'control', 'control.c')

util.makePlugin(pluginEnvironment, 'eqfil', 'eqfil.c')
util.makePlugin(pluginEnvironment, 'pvsbuffer', 'pvsbuffer.c')
util.makePlugin(pluginEnvironment, 'scoreline', 'scoreline.c')

if not buildOLPC:
  util.makePlugin(pluginEnvironment, 'ftest', 'ftest.c')

util.makePlugin(pluginEnvironment, 'mixer', 'mixer.cpp')
util.makePlugin(pluginEnvironment, 'modal4',
    ['modal4.c', 'physutil.c'])
util.makePlugin(pluginEnvironment, 'physmod', Split('''
    physmod.c physutil.c mandolin.c singwave.c
    fm4op.c moog1.c shaker.c bowedbar.c
'''))
util.makePlugin(pluginEnvironment, 'pitch',
    ['pitch.c', 'pitch0.c', 'spectra.c'])
util.makePlugin(pluginEnvironment, 'scansyn',
    ['scansyn.c', 'scansynx.c'])
util.makePlugin(pluginEnvironment, 'ambicode1',
    ['ambicode1.c'])

sfontEnvironment = pluginEnvironment.Clone()
if util.compilerGNU():
    sfontEnvironment.Append(CCFLAGS = ['-fno-strict-aliasing'])
if sys.byteorder == 'big':
    sfontEnvironment.Append(CCFLAGS = ['-DWORDS_BIGENDIAN'])
util.makePlugin(sfontEnvironment, 'sfont', ['sfont.c'])

if not buildOLPC:
  util.makePlugin(pluginEnvironment, 'babo', ['babo.c'])

util.makePlugin(pluginEnvironment, 'barmodel', ['bilbar.c'])
util.makePlugin(pluginEnvironment, 'compress', ['compress.c'])
util.makePlugin(pluginEnvironment, 'grain4', ['grain4.c'])

if not buildOLPC:
  util.makePlugin(pluginEnvironment, 'hrtferX', ['hrtferX.c'])

util.makePlugin(pluginEnvironment, 'loscilx', ['loscilx.c'])
util.makePlugin(pluginEnvironment, 'minmax', ['minmax.c'])
util.makePlugin(pluginEnvironment, 'cs_pan2', ['pan2.c'])
util.makePlugin(pluginEnvironment, 'phisem', ['phisem.c'])
util.makePlugin(pluginEnvironment, 'pvoc', Split('''
    dsputil.c pvadd.c pvinterp.c pvocext.c
    pvread.c ugens8.c vpvoc.c pvoc.c
'''))
util.makePlugin(pluginEnvironment, 'cs_pvs_ops', Split('''
    ifd.c partials.c psynth.c pvsbasic.c
    pvscent.c pvsdemix.c pvs_ops.c pvsband.c
'''))
util.makePlugin(pluginEnvironment, 'stackops', ['stackops.c'])

if not buildOLPC:
  util.makePlugin(pluginEnvironment, 'vbap',
           ['vbap.c', 'vbap_eight.c', 'vbap_four.c',
            'vbap_sixteen.c', 'vbap_zak.c'])

util.makePlugin(pluginEnvironment, 'vaops', ['vaops.c'])
util.makePlugin(pluginEnvironment, 'harmon', ['harmon.c'])
util.makePlugin(pluginEnvironment, 'ampmidid', ['ampmidid.cpp'])
util.makePlugin(pluginEnvironment, 'cs_date', ['date.c'])
util.makePlugin(pluginEnvironment, 'system_call', ['system_call.c'])
util.makePlugin(pluginEnvironment, 'ptrack', ['pitchtrack.c'])
util.makePlugin(pluginEnvironment, 'mutexops', ['mutexops.cpp'])
util.makePlugin(pluginEnvironment, 'partikkel', ['partikkel.c'])
util.makePlugin(pluginEnvironment, 'shape', ['shape.c'])

if buildOLPC :
    oggEnvironment = pluginEnvironment.Clone()
    oggEnvironment.Append(LIBS=['vorbisfile', 'vorbis', 'ogg'])
    util.makePlugin(oggEnvironment, 'ogg', ['ogg.c'])
    util.makePlugin(oggEnvironment, 'oggplay', ['oggplay.c'])

util.makePlugin(pluginEnvironment, 'vosim', ['Vosim.c'])

util.makePlugin(pluginEnvironment, 'gabnew', Split('''
    gab/tabmorph.c  gab/hvs.c
    gab/sliderTable.c
    gab/newgabopc.c
'''))
util.makePlugin(pluginEnvironment, 'hrtfnew', 'hrtfopcodes.c')

if not buildOLPC:
    jackFound = configure.CheckHeader("jack/jack.h", language = "C")
    if jackFound:
        jpluginEnvironment = pluginEnvironment.Clone()
        if util.platform == 'linux':
            jpluginEnvironment.Append(LIBS = ['jack', 'asound', 'pthread'])
        elif util.platform == 'win32':
            jpluginEnvironment.Append(LIBS = ['jackdmp', 'pthread'])
        else:
            jpluginEnvironment.Append(LIBS = ['pthread', 'jack'])
        util.makePlugin(jpluginEnvironment, 'jackTransport', 'jackTransport.c')
    if configure.CheckHeader("boost/any.hpp", language = "C++"):
        util.makePlugin(pluginEnvironment, 'chua', 'chua/ChuaOscillator.cpp')
    if configure.CheckHeader("gmm/gmm.h", language = "C++"):
        util.makePlugin(pluginEnvironment, 'linear_algebra', 'linear_algebra.cpp')

if commonEnvironment['buildImageOpcodes'] == '1':
    if not configure.CheckHeader("png.h", language="C"):
        util.fatal("You specified buildImageOpcodes but libpng was not found")
    if not configure.CheckHeader("zlib.h", language = "C"):
        util.fatal("You specified buildImageOpcodes but zlib was not found")
    util.confDecision('Building image opcodes')
    imgEnvironment = pluginEnvironment.Clone()
    imgEnvironment.Append(LIBS= Split(''' png z '''))
    util.makePlugin(imgEnvironment, 'image', ['imageOpcodes.c'])
else:
    util.confDecision('Not building image opcodes')


# OSC opcodes
if commonEnvironment['useOSC'] == '1':
    if not configure.CheckLibWithHeader("lo", "lo/lo.h", language = "C"):
        util.fatal("You specified useOSC but OSC was not found.")
    util.confDecision("Building OSC plugin.")
    oscEnvironment = pluginEnvironment.Clone()
    oscEnvironment.Append(LIBS = ['lo', 'pthread'])
    if util.platform == 'win32':
        if util.compilerGNU():
            oscEnvironment.Append(SHLINKFLAGS = ['-Wl,--enable-stdcall-fixup'])
    util.makePlugin(oscEnvironment, 'osc', ['OSC.c'])
else:
    util.confDecision("Not building OSC plugin.")

# UDP opcodes

if commonEnvironment['useUDP'] != '0':
    util.confDecision("Building UDP plugins.")
    udpEnvironment = pluginEnvironment.Clone()
    udpEnvironment.Append(LIBS = ['pthread'])
    util.makePlugin(udpEnvironment, 'udprecv', ['sockrecv.c'])
    util.makePlugin(udpEnvironment, 'udpsend', ['socksend.c'])
else:
    util.confDecision("Not building UDP plugins.")

if commonEnvironment['buildFluidOpcodes']!='0':
    if not configure.CheckHeader("fluidsynth.h", language = "C"):
        util.fatal("You specified buildFluidOpcodes but fluidsynth was not found")
    util.confDecision("Building fluid opcodes.")
    fluidEnvironment = pluginEnvironment.Clone()
    fluidEnvironment.Append(LIBS        = ['fluidsynth'])
    if util.platform == 'win32':
        fluidEnvironment.Append(CPPFLAGS    = ['-DFLUIDSYNTH_NOT_A_DLL'])
        fluidEnvironment.Append(LIBS        = ['winmm', 'dsound'])
    elif util.platform == 'linux' or util.platform == 'darwin':
        fluidEnvironment.Append(LIBS        = ['pthread'])
    util.makePlugin(fluidEnvironment, 'fluidOpcodes',
                    ['fluidOpcodes/fluidOpcodes.cpp'])
else:
    util.confDecision("Not building fluid opcodes.")

# DSSI host
if commonEnvironment['buildDSSI'] == '1':
    if not configure.CheckHeader("ladspa.h", language = "C"):
        util.fatal("You specified buildDSSI but LADSPA was not found")
    if not configure.CheckHeader("dssi.h", language = "C"):
        util.fatal("You specified buildDSSI but DSSI was not found")
    if not configure.CheckLibWithHeader('asound',
     'alsa/asoundlib.h', language="C", autoadd = False):
        util.fatal("You specified buildDSSI but ALSA was not found")
    util.confDecision("Building DSSI plugin host opcodes.")
    dssiEnvironment = pluginEnvironment.Clone()
    dssiEnvironment.Append(LIBS = ['dl'])
    dssiSrc = ['dssi4cs/src/load.c', 'dssi4cs/src/dssi4cs.c']
    util.makePlugin(dssiEnvironment, 'dssi4cs', dssiSrc)
else:
    util.confDecision("Not building DSSI plugin host opcodes.")

# Loris opcodes

if commonEnvironment['buildLoris'] == '1':
    if not configure.CheckHeader("Opcodes/Loris/src/loris.h"):
        util.fatal("You specified buildLoris but Loris was not found")
    if not configure.CheckHeader("fftw3.h"):
        util.fatal("You specified buildLoris but fftw3.h was not found")
    util.confDecision("Building Loris Python extension and Csound opcodes.")
    # For Loris, we build only the loris Python extension module and
    # the Csound opcodes (modified for Csound 5).
    # It is assumed that you have copied all contents of the Loris
    # distribution into the csound5/Opcodes/Loris directory, e.g.
    # csound5/Opcodes/Loris/src/*, etc.
    lorisEnvironment = pluginEnvironment.Clone()
    lorisEnvironment.Append(CCFLAGS = '-DHAVE_FFTW3_H')
    if commonEnvironment['buildRelease'] == '0':
        lorisEnvironment.Append(CCFLAGS = '-DDEBUG_LORISGENS')
    if util.platform == 'win32':
        lorisEnvironment.Append(CCFLAGS = '-D_MSC_VER')
    if util.compilerGNU():
        lorisEnvironment.Prepend(LIBS = ['stdc++'])
        lorisEnvironment.Append(CCFLAGS = Split(
        '-Wno-comment -Wno-unknown-pragmas -Wno-sign-compare'))
    lorisEnvironment.Append(CPPPATH = Split(
        'Loris Loris/src'))
    lorisSources = glob.glob('Loris/src/*.[Cc]')
    if 'Loris/src/lorisgens.C' in lorisSources:
        lorisSources.remove('Loris/src/lorisgens.C')
    lorisLibrarySources = []
    for i in lorisSources:
        lorisLibrarySources += lorisEnvironment.SharedObject(i)
    lorisLibrary = lorisEnvironment.StaticLibrary(
        'lorisbase', lorisLibrarySources)
    lorisEnvironment.Prepend(LIBS = [lorisLibrary, 'fftw3'])
    # The following file has been patched for Csound 5
    # and you should update it from Csound 5 CVS.
    lorisOpcodes = util.makePlugin(
        lorisEnvironment, 'loris', ['Loris/lorisgens5.C'])
    lorisPythonEnvironment = lorisEnvironment.Clone()
    util.fixCFlagsForSwig(lorisPythonEnvironment)
    util.fixEnvForPython(lorisPythonEnvironment, configure)
    lorisPythonEnvironment.Append(SWIGPATH  = ['#./', '#./Opcodes/Loris/src'])
    lorisPythonEnvironment.Prepend(SWIGFLAGS = Split('''
        -module loris -c++ -includeall -verbose -outdir . -python
        -DHAVE_FFTW3_H
    '''))
    lorisPythonWrapper = lorisPythonEnvironment.SharedObject(
        'Loris/scripting/loris.i')
    lorisPythonEnvironment['SHLIBPREFIX'] = ''
    lorisPythonModule = util.makePythonModule(
        lorisPythonEnvironment, 'loris', lorisPythonWrapper)
else:
    util.confDecision("Not building Loris Python extension and Csound opcodes.")

# Python opcodes

if commonEnvironment['buildPythonOpcodes'] == '1':
    util.confDecision("Building Python opcodes.")
    pyEnvironment = pluginEnvironment.Clone()
    if not util.fixEnvForPython(pyEnvironment, configure):
        util.fatal("You specified buildPythonOpcodes but Python was not found")

    if util.platform == 'linux':
        pyEnvironment.Append(LIBS = ['util', 'dl', 'm'])
    elif util.platform == 'darwin':
        pyEnvironment.Append(LIBS = ['dl', 'm'])
    elif util.platform == 'win32':
        pyEnvironment['ENV']['PATH'] = os.environ['PATH']
        pyEnvironment.Append(SHLINKFLAGS = '--no-export-all-symbols')
    pythonOpcodes = util.makePlugin(
        pyEnvironment, 'py', ['py/pythonopcodes.c'])

# VST HOST OPCODES
if commonEnvironment['buildvst4cs'] == '1':
    if not configure.CheckLibWithHeader("fltk", "FL/Fl.H",
     language = "C++", autoadd = False):
        util.fatal("You specified buildvst4cs but FLTK was not found")
    util.confDecision("Building vst4cs opcodes.")
    vstHeader = "frontends/CsoundVST/vstsdk2.4/public.sdk/source/vst2.x/audioeffectx.h"
    if not configure.CheckHeader(vstHeader, language = "C++"):
        util.fatal("You specified buildvst4cs but the VST SDK was not found")
    vst4Environment = pluginEnvironment.Clone()
    vst4Environment.Append(CPPFLAGS = ['-DCS_VSTHOST'])
    vst4Environment.Append(CPPPATH  = ['#frontends/CsoundVST'])
    vst4Environment.Append(CPPFLAGS = ['-DHAVE_VST_SDK'])
    if (util.platform == 'win32' or util.platform == 'linux'):
        if util.compilerGNU():
            vst4Environment.Append(LIBS = Split(
                'fltk_images fltk_png fltk_z fltk_jpeg fltk'))
            vst4Environment.Append(LIBS = ['stdc++'])
        else:
            vst4Environment.Append(LIBS = Split(
                'fltkimages fltkpng fltkz fltkjpeg fltk'))
    else:
        vst4Environment.Append(LIBS = ['fltk'])
        vst4Environment.Append(LIBS = ['stdc++'])
        vst4Environment.Append(LINKFLAGS =
            ['-framework', 'carbon', '-framework', 'ApplicationServices'])
    util.makePlugin(vst4Environment, 'vst4cs', Split('''
                    vst4cs/src/vst4cs.cpp
                    vst4cs/src/fxbank.cpp
                    vst4cs/src/vsthost.cpp
                    '''))


# STK opcodes

if commonEnvironment['buildStkOpcodes'] == '1':
    if not configure.CheckHeader( "stk/include/Stk.h", language = "C++"):
        util.fatal("You specified buildStkOpcodes but STK was not found")
    util.confDecision('Building STK opcodes.')
    # For the STK opcodes, the STK distribution include, src, and rawwaves
    # directories should be copied thusly:
    #   csound5/Opcodes/stk/include
    #   csound5/Opcodes/stk/src
    #   csound5/Opcodes/stk/rawwaves
    # Then, the following sources (and any other future I/O or OS dependent
    # sources) should be ignored:
    removeSources = Split('''
        stk/src/InetWvIn.cpp    stk/src/InetWvOut.cpp
        stk/src/Mutex.cpp       stk/src/RtAudio.cpp
        stk/src/RtMidi.cpp
        stk/src/RtWvIn.cpp      stk/src/RtWvOut.cpp
        stk/src/Socket.cpp      stk/src/TcpClient.cpp
        stk/src/TcpServer.cpp   stk/src/Thread.cpp
        stk/src/UdpSocket.cpp
    ''')
    stkEnvironment = pluginEnvironment.Clone()
    if util.platform == 'win32':
        stkEnvironment.Append(CCFLAGS = '-D__OS_WINDOWS__')
    elif util.platform == 'linux':
        stkEnvironment.Append(CCFLAGS = '-D__OS_LINUX__')
    elif util.platform == 'darwin':
        stkEnvironment.Append(CCFLAGS = '-D__OS_MACOSX__')
    if sys.byteorder == 'big':
        stkEnvironment.Append(CCFLAGS = '-D__BIG_ENDIAN__')
    else:
        stkEnvironment.Append(CCFLAGS = '-D__LITTLE_ENDIAN__')
    stkEnvironment.Prepend(CPPPATH = Split(
        'stk/include stk/src ./ ./../include'))
    stkSources_ = glob.glob('stk/src/*.cpp')
    stkSources = []
    for source in stkSources_:
        stkSources.append(source.replace('\\', '/'))
    for removeMe in removeSources:
        stkSources.remove(removeMe)
    stkLibrarySources = []
    for i in stkSources:
        stkLibrarySources += stkEnvironment.SharedObject(i)
    stkLibrary = stkEnvironment.StaticLibrary('stk_base', stkLibrarySources)
    stkEnvironment.Prepend(LIBS = ['stk_base'])
    if util.compilerGNU():
        stkEnvironment.Append(LIBS = ['stdc++'])
    elif util.platform == 'linux' or util.platform == 'darwin':
        stkEnvironment.Append(LIBS = ['pthread'])
    # This is the one that actually defines the opcodes.
    # They are straight wrappers, as simple as possible.
    stk = util.makePlugin(stkEnvironment, 'stk', ['stk/stkOpcodes.cpp'])
    Depends(stk, stkLibrary)
