#! python
# -*- coding: utf-8 -*-

# Lancer la commande: /home/moi/Csound/pycsound.sh morphdemo.py

# This is the Loris C++ Class Library, implementing analysis, manipulation, and synthesis of digitized sounds using the Reassigned Bandwidth-Enhanced Additive Sound Model.
# Generates several morphs between a clarinet, a flute, and a cello. The results can be compared to those in the "source".

import loris, os, time

print '(in %s)\n' % os.getcwd()
print '(using Loris version %s)\n' % loris.version()

srcdir = '/home/moi/Samples/Loris'

# The analysis process is as follows:
# - configure the analyzer (the flute and clarinet use the same analyzer configuration)
# - analyze, yielding a collection of partials
# - extract a reference envelope and distill partials
# (this reduces the number of partials considerably by connecting and condensing related partials; for example, in quasi-harmonic sounds, the distillation process yields one partial per harmonic)
# - a test synthesis of the distilled partials is performed, just as a sanity check, and to verify the suitability of the analysis configuration and distillation parameters


#########################
# analyze clarinet tone #
#########################
print 'analyzing clarinet 3G# (%s)' % time.ctime(time.time())

a = loris.Analyzer(.8*415, 1.0*415)

cf = loris.AiffFile( os.path.join(srcdir, 'clarinet_source.aiff') )
v = cf.samples()
samplerate = cf.sampleRate()
clar = a.analyze( v, samplerate )
print 'using fundamental as reference'
env = loris.createFreqReference( clar, 350, 500, 20 )
loris.channelize( clar, env, 1 )
loris.distill( clar )


#########################
#  analyze flute tone   #
#########################
print 'analyzing flute 3D (%s)' % time.ctime(time.time())

a = loris.Analyzer( 270 )

ff = loris.AiffFile( os.path.join(srcdir, 'flute_source.aiff') )
v = ff.samples()
samplerate = ff.sampleRate()
flut = a.analyze( v, samplerate )
print 'using fundamental as reference'
flut_env = loris.createFreqReference( flut, 250, 500, 20 )
loris.channelize( flut, flut_env, 1 )
loris.distill( flut )


#########################
#  analyze cello tone   #
#########################
print 'analyzing cello 2D# (%s)' % time.ctime(time.time())

a = loris.Analyzer( 250 )

celf = loris.AiffFile( os.path.join(srcdir, 'cello_source.aiff') )
v = celf.samples()
samplerate = celf.sampleRate()
cel = a.analyze( v, samplerate )
print 'using third harmonic as reference'
third = loris.createFreqReference( cel, 400, 500, 20 )
loris.channelize( cel, third, 3 )
loris.distill( cel )


##############################
#  effect on clarinet tone   #
##############################
print 'shifting clarinet pitch down by six half steps'
loris.shiftPitch( clar, loris.BreakpointEnvelopeWithValue( -600 ) )
print 'doubling amplitude'
loris.scaleAmp( clar, loris.BreakpointEnvelopeWithValue( 2 ) )


#################################
#   perform temporal dilation   #
#################################
# Times are the beginning and end times of the attack and the release. To change the duration of the morph, change the target times (tgt_times), as well as the morphing function, mf, defined below.

flute_times = [0.175, 0.4, 2.15, 2.31]
clar_times = [0., 0.185, 1.9, 2.15]
cel_times = [0., 0.13, 2.55, 3.9]
tgt_times = [0., 0.19, 3., 3.25]

print 'dilating sounds to match', tgt_times, '(%s)' % time.ctime(time.time())
print 'flute times:', flute_times
loris.dilate( flut, flute_times, tgt_times)
print 'clarinet times:', clar_times
loris.dilate( clar, clar_times, tgt_times )
print 'cello times:', cel_times
loris.dilate( cel, cel_times, tgt_times )

############################################
#   synthesize and save dilated sources    #
############################################
# Save the synthesized samples files, and SDIF files for each dilated source.

fname = '/home/moi/Tempo/flute.dilated.aiff'
print 'synthesizing', fname, '(%s)' % time.ctime(time.time())
loris.exportAiff( fname, loris.synthesize( flut, samplerate ), samplerate, 16, 1 )

fname = '/home/moi/Tempo/flute.dilated.sdif'
print 'exporting sdif file:', fname, '(%s)' % time.ctime(time.time())
loris.exportSdif( fname, flut )

fname = '/home/moi/Tempo/clar.dilated.aiff'
print 'synthesizing', fname, '(%s)' % time.ctime(time.time())
loris.exportAiff( fname, loris.synthesize( clar, samplerate ), samplerate, 16, 1 )

fname = '/home/moi/Tempo/clarinet.dilated.sdif'
print 'exporting sdif file:', fname, '(%s)' % time.ctime(time.time())
loris.exportSdif( fname, clar )

fname = '/home/moi/Tempo/cello.dilated.aiff'
print 'synthesizing', fname, '(%s)' % time.ctime(time.time())
loris.exportAiff( fname, loris.synthesize( cel, samplerate ), samplerate, 16, 1 )

fname = '/home/moi/Tempo/cello.dilated.sdif'
print 'exporting sdif file:', fname, '(%s)' % time.ctime(time.time())
loris.exportSdif( fname, cel )

#####################
#   perform morphs  #
#####################
# Morphs are from the first sound to the second over the time 0.6 to 1.6 seconds.

mf = loris.BreakpointEnvelope()
mf.insertBreakpoint( 0.6, 0 )
mf.insertBreakpoint( 1.6, 1 )

samplerate = 44100.

print 'morphing flute and clarinet (%s)' % time.ctime(time.time())
m = loris.morph( clar, flut, mf, mf, mf )
loris.exportAiff( '/home/moi/Tempo/clariflute.aiff', loris.synthesize( m, samplerate ), samplerate, 16, 1 )
print 'exporting sdif file clariflute.aiff', '(%s)' % time.ctime(time.time())
loris.exportSdif( '/home/moi/Tempo/clariflute.sdif', m )

loris.exportAiff( '/home/moi/Tempo/flutinet.aiff', loris.synthesize( loris.morph( flut, clar, mf, mf, mf ), samplerate ), samplerate, 16, 1 )

print 'morphing flute and cello (%s)' % time.ctime(time.time())
print 'shifting flute pitch down by eleven half steps'
flut_low = flut.copy()
loris.shiftPitch( flut_low, loris.BreakpointEnvelopeWithValue( -1100 ) )
loris.exportAiff( '/home/moi/Tempo/cellute.aiff', loris.synthesize( loris.morph( cel, flut_low, mf, mf, mf ), samplerate ), samplerate, 16, 1 )
loris.exportAiff( '/home/moi/Tempo/flutello.aiff', loris.synthesize( loris.morph( flut_low, cel, mf, mf, mf ), samplerate ), samplerate, 16, 1 )

print 'morphing flute and cello again (%s)' % time.ctime(time.time())
print 'shifting flute pitch up by one half step'
loris.shiftPitch( flut, loris.BreakpointEnvelopeWithValue( 100 ) )

for it in flut:
    it.setLabel( it.label()*2)

print 'exporting Spc files for pre-morphed flute and cello sounds.'
print 'exporting Spc file flute.premorph.spc', '(%s)' % time.ctime(time.time())
loris.exportSpc('/home/moi/Tempo/flute.premorph.spc', flut, 62, 0)
print 'exporting Spc file cello.premorph.spc', '(%s)' % time.ctime(time.time())
loris.exportSpc('/home/moi/Tempo/cello.premorph.spc', cel, 50, 0)

m = loris.morph( cel, flut, mf, mf, mf )
loris.exportAiff( '/home/moi/Tempo/cellute2.aiff', loris.synthesize( m, samplerate ), samplerate, 16, 1 )

print 'exporting Spc file for second flute and cello morph.'
print 'exporting Spc file cellute2.spc', '(%s)' % time.ctime(time.time())
loris.exportSpc('/home/moi/Tempo/cellute2.spc', m, 50, 0)

m = loris.morph( flut, cel, mf, mf, mf )
loris.exportAiff( '/home/moi/Tempo/flutello2.aiff', loris.synthesize( m, samplerate ), samplerate, 16, 1 )

# all done
print 'hey, I\'m spent. (%s)' % time.ctime(time.time())
