#!/usr/bin/env python
"""
This scripts has following dependencies:
  * csound (>= 6.12) in order to play .mtx.wav files (see loristrck_pack)
  * the python module `sounddevice` to play a sound directly

"""
import argparse
import os
import loristrck
import tempfile
import sys
import subprocess

parser = argparse.ArgumentParser()
parser.add_argument("--speed", default=1, type=float)
parser.add_argument("--transposition", default=0, type=float, help="transposition in semitones")
parser.add_argument("-o", "--out", default="dac", 
                    help="Play / Save the samples. Use dac to play in realtime, or a .wav "
                         "of .aif path to synthesize to that file")
parser.add_argument("inputfile", help="A .sdif or .mtx.wav file (as generated via loristrck_pack")
args = parser.parse_args()


def printerr(s):
    print(s, file=sys.stderr)


def play_sdif(inputfile, out, sr=44100, speed=1, transposition=0):
    partials, labels = loristrck.read_sdif(inputfile)
    if speed != 1:
        partials = loristrck.util.partials_stretch(partials, factor=1/speed, inplace=True)
    if transposition != 0:
        partials = loristrck.util.partials_transpose(partials, transposition, inplace=True)
    samples = loristrck.synthesize(partials, sr)
    if out == "dac":
        play_samples(samples, sr=sr)
    else:
        loristrck.wavwrite(out, samples, sr)
        

def play_samples(samples, sr):
    try:
        import sounddevice as sd
        sd.play(samples, sr, blocksize=4096)
        sd.wait()
    except ImportError:
        play_samples_via_soundfile(samples, sr)


def play_samples_via_soundfile(samples, sr):
    outfile = tempfile.mktemp(suffix=".wav", prefix="loristrck-")
    loristrck.wavwrite(outfile, samples, sr)
    play_sndfile(outfile)


def play_sndfile(sndfile):
    loristrck.util.open_with_standard_app(sndfile) 


def csound_in_path():
    import shutil
    return shutil.which("csound") is not None


def play_mtx(wavfile, out, speed=1, gain=1, freqscale=1, saveas=''):
    import string
    if not csound_in_path():
        print("csound should be installed in order to play a .mtx.wav file", file=sys.stderr)
        sys.exit(-1)
    template = string.Template("""
<CsoundSynthesizer>
<CsOptions>
-o$out
</CsOptions>
<CsInstruments>

sr = 44100
ksmps = 128
nchnls = 2
0dbfs = 1.0

gispectrum ftgen 0, 0, 0, -1, "$mtxfile", 0, 0, 0

instr 1
  ifn = gispectrum
  iskip      tab_i 0, ifn
  idt        tab_i 1, ifn
  inumcols   tab_i 2, ifn
  inumrows   tab_i 3, ifn
  itimestart tab_i 4, ifn
  inumpartials = inumcols / 3 
  imaxrow = inumrows - 2
  it = ksmps / sr
  ispeed init $speed
  ifreqscale init $freqscale
  idur = imaxrow * idt / ispeed
  
  kplayhead = phasor:k(ispeed/idur)*idur
  krow = kplayhead / idt
  kF[] getrowlin krow, ifn, inumcols, iskip, 0, 0, 3
  kA[] getrowlin krow, ifn, inumcols, iskip, 1, 0, 3
  kB[] getrowlin krow, ifn, inumcols, iskip, 2, 0, 3
  
  iflags = 0    ; uniform noise, no interpolation
  aout beadsynt kF, kA, kB, -1, iflags, ifreqscale
  
  kt timeinsts
  if(kt > idur) then
    event "e", 0, 0, 0
  endif
  aenv cosseg 0, 0.02, $gain, idur-0.02-0.1, $gain, 0.1, 0
  aout *= aenv
  outs aout, aout
endin

schedule 1, 0, -1

</CsInstruments>
<CsScore>
</CsScore>
</CsoundSynthesizer>
    """)
    csdstr = template.safe_substitute(out=out, mtxfile=wavfile, speed=str(speed), freqscale=str(freqscale), gain=str(gain))
    csd = tempfile.mktemp(suffix=".csd", prefix="loristrck-")
    with open(csd, "w") as f:
        f.write(csdstr)
    cmd = ['csound', '-d', '-m0', csd]
    subprocess.call(cmd)


ext = os.path.splitext(args.inputfile)[1].lower()
if ext == '.sdif':
    play_sdif(args.inputfile, out=args.out, speed=args.speed, transposition=args.transposition)
elif ext == '.wav':
    play_mtx(args.inputfile, out=args.out, speed=args.speed, freqscale=loristrck.i2r(args.transposition))
else:
    print("Input should be a sdif file or a packed matrix (mtx.wav)", file=sys.stderr)
    sys.exit(-1)
