diff options
Diffstat (limited to 'site/udo/scss/elasticlip.udo')
-rwxr-xr-x | site/udo/scss/elasticlip.udo | 823 |
1 files changed, 823 insertions, 0 deletions
diff --git a/site/udo/scss/elasticlip.udo b/site/udo/scss/elasticlip.udo new file mode 100755 index 0000000..e5bd2ee --- /dev/null +++ b/site/udo/scss/elasticlip.udo @@ -0,0 +1,823 @@ +#ifndef UDO_SCSS_ELASTICLIP
+#define UDO_SCSS_ELASTICLIP ##
+/*
+ SCSS segemented timestretch record/playback loop engine
+
+ This file is part of the SONICS UDO collection by Richard Knight 2024
+ License: GPL-2.0-or-later
+ http://1bpm.net
+*/
+
+#include "/bussing.udo"
+#include "/wavetables.udo"
+#include "/interop.udo"
+#include "/sequencing.udo"
+#include "/sequencing_scheduled.udo"
+#include "/table_tools.udo"
+#include "/pvs_tools.udo"
+
+/*
+ Control Items
+
+ 0 wave L
+ 1 wave R
+ 2 warp divisions per beat
+ 3 duration
+ 4 beats length
+ 5 utilised length
+ 6 warp mode ; 0 = repitch , 1 = texture , 2 = mincer , 2 = pvstab
+ 7 pitch, in semitones from original
+ 8 amp
+ 9 fft size
+ 10 texture window size
+ 11 texture random
+ 12 texture overlap
+ 13 loop switch
+ 14 warp switch
+ 15 texture window type ; 0 = hanning, 1 = hamming, 2 = half sine
+ 16 utilised start
+ 17 phase lock
+ 18 sample rate
+ 19 + = warp points
+*/
+gSecp_clipnames[] init 9999
+giecp_fnclips[] init 9999
+giecp_clipindexmax = 0
+
+giecp_controlitemnum = 19
+
+
+#ifndef ECP_NORECORDING
+#ifndef ECP_RECORDBUFFERTIME
+#define ECP_RECORDBUFFERTIME #10#
+#end
+giecp_recordbufferduration = $ECP_RECORDBUFFERTIME
+giecp_recordbufferL ftgen 0, 0, -(giecp_recordbufferduration*sr), -7, 0
+giecp_recordbufferR ftgen 0, 0, -(giecp_recordbufferduration*sr), -7, 0
+#end
+
+
+opcode ecp_set_warppoint, 0, iii
+ iclipindex, ipointindex, ivalue xin
+ ifndata = giecp_fnclips[iclipindex]
+ imax = tab_i(4, ifndata) * tab_i(2, ifndata)
+ if (ipointindex < imax) then
+ ipointindex += giecp_controlitemnum
+ tablew ivalue, ipointindex, ifndata
+ endif
+endop
+
+
+
+opcode ecp_get_audiofn, ii, i
+ iclipindex xin
+ ifndata = giecp_fnclips[iclipindex]
+ ifnL tab_i 0, ifndata
+ ifnR tab_i 1, ifndata
+ xout ifnL, ifnR
+endop
+
+opcode ecp_get_name, S, i
+ iclipindex xin
+ xout gSecp_clipnames[iclipindex]
+endop
+
+opcode ecp_set_name, 0, iS
+ iclipindex, Sname xin
+ gSecp_clipnames[iclipindex] = Sname
+endop
+
+opcode ecp_get_duration, i, i
+ iclipindex xin
+ xout tab_i(3, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_get_divisions, i, i
+ iclipindex xin
+ xout tab_i(2, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_set_pitch, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 7, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_get_pitch, i, i
+ iclipindex xin
+ xout tab_i(7, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_get_warpmode, i, i
+ iclipindex xin
+ xout tab_i(6, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_set_warpmode, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 6, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_set_texturesize, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 10, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_get_texturesize, i, i
+ iclipindex xin
+ xout tab_i(10, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_set_texturerandom, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 11, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_get_texturerandom, i, i
+ iclipindex xin
+ xout tab_i(11, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_set_textureoverlap, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 12, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_get_textureoverlap, i, i
+ iclipindex xin
+ xout tab_i(12, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_set_loop, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 13, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_get_loop, i, i
+ iclipindex xin
+ xout tab_i(13, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_set_warp, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 14, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_get_warp, i, i
+ iclipindex xin
+ xout tab_i(14, giecp_fnclips[iclipindex])
+endop
+
+opcode ecp_set_texturewindow, 0, ii
+ iclipindex, ivalue xin
+ tabw_i ivalue, 15, giecp_fnclips[iclipindex]
+endop
+
+opcode ecp_get_texturewindow, i, i
+ iclipindex xin
+ xout tab_i(15, giecp_fnclips[iclipindex])
+endop
+
+
+opcode ecp_randomise_warppoints, 0, io
+ iclipindex, imode xin
+ ipoints = ecp_get_duration(iclipindex) * ecp_get_divisions(iclipindex)
+ iduration = ecp_get_duration(iclipindex)
+ iaveragedivision = iduration / ipoints
+ ilasttime = (imode == -1) ? iduration : 0
+ index = 0
+ while (index < ipoints) do
+ if (imode == 0) then
+ ecp_set_warppoint iclipindex, index, random(0, iduration)
+ else
+ itime = (imode == 1) ? min(random(ilasttime, ilasttime + iaveragedivision), iduration) : max(random(ilasttime - iaveragedivision, ilasttime), 0)
+ ecp_set_warppoint iclipindex, index, itime
+ ilasttime = itime
+ endif
+ index += 1
+ od
+endop
+
+
+opcode ecp_replacetables, 0, iiop
+ iclipindex, ifnL, ifnR, ireplaceall xin
+ ifndata = giecp_fnclips[iclipindex]
+
+ ifnLoriginal tab_i 0, ifndata
+ ifnRoriginal tab_i 1, ifndata
+ if (ifnL == ifnLoriginal) then
+ goto complete
+ endif
+ ioriginallen table 3, ifndata
+ ilen = ftlen(ifnL) / ftsr(ifnL)
+
+ if (ireplaceall == 1) then
+ index = 0
+ while (index < lenarray(giecp_fnclips)) do
+ if (index != iclipindex && giecp_fnclips[index] > 0) then
+ itfnL tab_i 0, giecp_fnclips[index] ; assuming ifnR will do as well
+ if (itfnL == ifnLoriginal) then
+ tablew ifnL, 0, giecp_fnclips[index]
+ tablew ifnR, 1, giecp_fnclips[index]
+ endif
+ endif
+ index += 1
+ od
+
+ if (ftexists(ifnLoriginal) == 1) then
+ ftfree ifnLoriginal, 0
+ endif
+ if (ifnRoriginal != 0 && ftexists(ifnRoriginal) == 1) then
+ ftfree ifnRoriginal, 0
+ endif
+ else
+ tablew ifnL, 0, ifndata
+ tablew ifnR, 1, ifndata
+
+ endif
+
+
+ ; needs to be done for all if ireplaceall is set
+ if (ioriginallen != ilen) then
+ tablew ilen, 3, ifndata
+ ibeats table 4, ifndata
+ idivisionsperbeat table 2, ifndata
+ itotalpoints = ibeats * idivisionsperbeat
+ iparttime = ilen / itotalpoints
+ index = giecp_controlitemnum
+ itime = 0
+ while (index < ftlen(ifndata)) do
+ tablew itime, index, ifndata
+ itime += iparttime
+ index += 1
+ od
+ endif
+complete:
+endop
+
+
+opcode ecp_removeclip, 0, i
+ iclipindex xin
+ ifndata = giecp_fnclips[iclipindex]
+ ifnL tab_i 0, ifndata
+ ifnR tab_i 1, ifndata
+
+ iremovefn = 1
+ index = 0
+ while (index < lenarray(giecp_fnclips)) do
+ if (index != iclipindex && giecp_fnclips[index] > 0) then
+ itfnL tab_i 0, giecp_fnclips[index] ; assuming ifnR will do as well
+ if (itfnL == ifnL) then
+ iremovefn = 0
+ goto complete
+ endif
+ endif
+ index += 1
+ od
+complete:
+ if (iremovefn == 1) then
+ ftfree ifnL, 0
+ if (ifnR > 0) then
+ ftfree ifnR, 0
+ endif
+ endif
+ ftfree ifndata, 0
+ giecp_fnclips[iclipindex] = 0
+endop
+
+opcode ecp_importclip, i, i
+ ifndata xin
+ iclipindex = giecp_clipindexmax
+ giecp_clipindexmax += 1
+ gSecp_clipnames[iclipindex] = "Imported" ; defunct really: TODO remove
+ giecp_fnclips[iclipindex] = ifndata
+ xout iclipindex
+endop
+
+/*
+ Add clip to runtime engine
+
+ iclipindex ecp_addclip Sname, ifnL, ifnR, ibeats [, idivisionsperbeat = 4]
+
+ iclipindex index of the clip for recall
+ Sname name of the clip, can be passed blank to default
+ ifnL left ftable of audio
+ ifnR right ftable of audio, can be passed as 0 if mono
+ ibeats the length of the clip in beats
+ idivisionsperbeat resolution of markers per beat, default is 4
+
+*/
+opcode ecp_addclip, i, Siiij
+ Sname, ifnL, ifnR, ibeats, idivisionsperbeat xin
+ idivisionsperbeat = (idivisionsperbeat == -1) ? 4 : idivisionsperbeat
+ iclipindex = giecp_clipindexmax
+ giecp_clipindexmax += 1
+
+ if (strcmp(Sname, "") == 0) then
+ Sname = sprintf("clip %d", iclipindex + 1)
+ endif
+ ilen = ftlen(ifnL) / ftsr(ifnL)
+ itotalpoints = ibeats * idivisionsperbeat
+ iparttime = ilen / itotalpoints
+ ifndata ftgen 0, 0, -(itotalpoints+giecp_controlitemnum), -2, 0
+
+ tablew ifnL, 0, ifndata
+ tablew ifnR, 1, ifndata
+ tablew idivisionsperbeat, 2, ifndata
+ tablew ilen, 3, ifndata ; seconds length
+ tablew ibeats, 4, ifndata ; beats length
+ tablew ilen, 5, ifndata ; seconds utilised length
+ tablew 0, 6, ifndata ; warp mode
+ tablew 0, 7, ifndata ; pitch
+ tablew 1, 8, ifndata ; amp
+ tablew 512, 9, ifndata ; fft size
+ tablew 4410, 10, ifndata ; texture window size
+ tablew 441, 11, ifndata ; texture random
+ tablew 2, 12, ifndata ; texture overlap
+ tablew 0, 13, ifndata ; whether to loop or one shot
+ tablew 0, 14, ifndata ; whether to warp or straight playback
+ tablew 0, 15, ifndata ; texture mode window shape, corresponds to hanning, hamming, half sine
+ tablew 0, 16, ifndata ; utilised start
+ tablew 1, 17, ifndata ; phase lock
+ tablew ftsr(ifnL), 18, ifndata ; samplerate
+
+ index = giecp_controlitemnum
+ itime = 0
+ while (index < ftlen(ifndata)) do
+ tablew itime, index, ifndata
+ itime += iparttime
+ index += 1
+ od
+
+ gSecp_clipnames[iclipindex] = Sname
+ giecp_fnclips[iclipindex] = ifndata
+ xout iclipindex
+endop
+
+
+opcode ecp_loadsound, i, Sio
+ Spath, ibeats, iforcemono xin
+ ichnls = (iforcemono == 1) ? 1 : filenchnls(Spath)
+ ifnL ftgen 0, 0, 0, 1, Spath, 0, 0, 1
+ if (ichnls == 2) then
+ ifnR ftgen 0, 0, 0, 1, Spath, 0, 0, 2
+ else
+ ifnR = 0
+ endif
+ iclipindex = ecp_addclip(Spath, ifnL, ifnR, ibeats, 4)
+ xout iclipindex
+endop
+
+
+opcode ecp_setaudiounique, 0, i
+ iclipindex xin
+ ifndata = giecp_fnclips[iclipindex]
+ ifnL tab_i 0, ifndata
+ ifnR tab_i 1, ifndata
+
+ irequired = 0
+ index = 0
+ while (index < lenarray(giecp_fnclips)) do
+ if (index != iclipindex && giecp_fnclips[index] > 0) then
+ itfnL tab_i 0, giecp_fnclips[index] ; assuming ifnR will do as well
+ if (itfnL == ifnL) then
+ irequired = 1
+ goto complete
+ endif
+ endif
+ index += 1
+ od
+complete:
+ if (irequired == 1) then
+ isize = ftlen(ifnL)
+ ifnLnew ftgen 0, 0, -isize, -2, 0
+ tableicopy ifnLnew, ifnL
+ tabw_i ifnLnew, 0, ifndata
+ if (ifnR > 0) then
+ ifnRnew ftgen 0, 0, -isize, -2, 0
+ tableicopy ifnRnew, ifnR
+ tabw_i ifnRnew, 1, ifndata
+ endif
+ endif
+endop
+
+
+opcode ecp_cloneclip, i, i
+ iclipindexfrom xin
+ iclipindexto = giecp_clipindexmax
+ giecp_clipindexmax += 1
+
+ ifndatafrom = giecp_fnclips[iclipindexfrom]
+ ifndatato ftgen 0, 0, -ftlen(ifndatafrom), -2, 0
+
+ gSecp_clipnames[iclipindexto] = gSecp_clipnames[iclipindexfrom]
+ tableicopy ifndatato, ifndatafrom
+
+ giecp_fnclips[iclipindexto] = ifndatato
+ xout iclipindexto
+endop
+
+
+instr ecp_stop
+ icbid = p4
+ turnoff2 nstrnum("ecp_playback") + (icbid / 1000000), 4, 1
+ turnoff
+endin
+
+
+opcode ecp_getwaveform, i, io
+ iclipindex, isamples xin
+ ifnL table 0, giecp_fnclips[iclipindex]
+ ifndata tab_overview ifnL, isamples
+ xout ifndata
+endop
+
+
+instr ecp_stopaudition
+ icbid = p4
+ turnoff2 nstrnum("ecp_playaudition") + (icbid / 1000000), 4, 1
+ turnoff
+endin
+
+instr ecp_playaudition_complete
+ icbid = p4
+ io_sendstring("callback", sprintf("{\"cbid\":%d,\"status\":0}", icbid))
+ turnoff
+endin
+
+instr ecp_playaudition
+ icbid = p4
+ iclipindex = p5
+ iduration = p6
+ ichannel = p7
+ p1 += (icbid / 1000000)
+ io_sendstring("callback", sprintf("{\"cbid\": %d, \"status\": 1}", icbid))
+ aL, aR subinstr "ecp_playback_tst", icbid, iclipindex, iduration
+ outs aL, aR ; channels??
+
+ kreleasing init 0
+ if (lastcycle:k() == 1 || (kreleasing == 0 && release:k() == 1)) then
+ kreleasing = 1
+ schedulek("ecp_playaudition_complete", 0, 1, icbid)
+ endif
+endin
+
+
+instr ecp_playback_tst
+ icbid = p4
+ iclipindex = p5
+ iduration = p6
+ istartoffset = p7
+
+ ifndata = giecp_fnclips[iclipindex]
+ ifnL tab_i 0, ifndata
+ ifnR tab_i 1, ifndata
+ idivisions tab_i 2, ifndata
+ itotalduration tab_i 3, ifndata
+
+ iutilisedlength tab_i 5, ifndata
+ iwarpmode tab_i 6, ifndata ; 0 = repitch, 1 = texture, 2 = mincer, 3 = pvstab
+ kpitch = pow:k(2, (tab:k(7, ifndata) / 12))
+ kamp tab 8, ifndata
+ ifftsize tab_i 9, ifndata
+ iwindowsize tab_i 10, ifndata
+ irandwin tab_i 11, ifndata
+ ioverlap tab_i 12, ifndata
+ iloop tab_i 13, ifndata
+ iwarp tab_i 14, ifndata
+ iwindowtype tab_i 15, ifndata
+ istart = tab_i(16, ifndata) + istartoffset
+ kphaselock tab 17, ifndata
+ isr tab_i 18, ifndata
+
+ if (iwindowtype == 0) then
+ iwindow = gifnHanning
+ elseif (iwindowtype == 1) then
+ iwindow = gifnHamming
+ else
+ iwindow = gifnHalfSine
+ endif
+
+ if (iwarp == 1) then
+ atime linseg istart, iduration, iutilisedlength
+ else
+ atime = (phasor(1 / itotalduration) * (iutilisedlength - istart)) + istart
+ endif
+
+
+ ; repitch
+ if (iwarp == 0) then
+ aptime = atime * ftsr(ifnL) * kpitch
+ aoutL table3 aptime, ifnL, 0
+ if (ifnR != 0) then
+ aoutR table3 aptime, ifnR, 0
+ else
+ aoutR = aoutL
+ endif
+
+ ; texture
+ elseif (iwarpmode == 1) then
+ isradjust = isr / sr
+ aoutL sndwarp 1, atime, a(kpitch) * isradjust, ifnL, 0, iwindowsize, irandwin, ioverlap, iwindow, 1
+ if (ifnR != 0) then
+ aoutR sndwarp 1, atime, a(kpitch) * isradjust, ifnR, 0, iwindowsize, irandwin, ioverlap, iwindow, 1
+ else
+ aoutR = aoutL
+ endif
+
+ ; mincer
+ elseif (iwarpmode == 2) then
+ aoutL mincer atime, 1, kpitch, ifnL, kphaselock, ifftsize, 4
+ if (ifnR != 0) then
+ aoutR mincer atime, 1, kpitch, ifnR, kphaselock, ifftsize, 4
+ else
+ aoutR = aoutL
+ endif
+
+ ; pvs
+ elseif (iwarpmode == 3) then ; contentious benefit
+ ipvsbufL pvs_ifn2buffer ifnL, ifftsize, ifftsize / 4, ifftsize, 2
+ ffoutL pvsbufread k(atime), ipvsbufL
+ if (kpitch != 1) then
+ fscaleL pvscale ffoutL, kpitch
+ aoutL pvsynth fscaleL
+ else
+ aoutL pvsynth ffoutL
+ endif
+
+ if (ifnR != 0) then
+ ipvsbufR pvs_ifn2buffer ifnR, ifftsize, ifftsize / 4, ifftsize, 2
+ ffoutR pvsbufread k(atime), ipvsbufR
+ if (kpitch != 1) then
+ fscaleR pvscale ffoutR, kpitch
+ aoutR pvsynth fscaleR
+ else
+ aoutR pvsynth ffoutR
+ endif
+ else
+ ifnR = ifnL
+ endif
+ endif
+
+ aamp linseg 1, iduration * 0.9999, 1, iduration * 0.0001, 0
+
+ aoutL *= aamp * kamp
+ aoutR *= aamp * kamp
+ outs aoutL, aoutR
+endin
+
+
+instr ecp_playback
+ icbid = p4
+ iclipindex = p5
+
+ if (icbid > 0) then
+ p1 += icbid / 1000000
+ io_sendstring("callback", sprintf("{\"cbid\": %d, \"status\": 3}", icbid))
+ endif
+
+ Sbus = strget(p6)
+ if (strcmp(Sbus, "") == 0) then
+ Sbus = "main"
+ endif
+
+ kmincelock init 1
+
+ ifndata = giecp_fnclips[iclipindex]
+ ifnL table 0, ifndata
+ ifnR table 1, ifndata
+ idivisions table 2, ifndata
+ itotalduration table 3, ifndata
+
+ iwarpmode table 6, ifndata ; 0 = repitch, 1 = texture, 2 = pvs, 3 = mincer
+ kpitch = pow:k(2, (tab:k(7, ifndata) / 12))
+ kamp table 8, ifndata
+ ifftsize table 9, ifndata
+ iwindowsize table 10, ifndata
+ irandwin table 11, ifndata
+ ioverlap table 12, ifndata
+ iloop table 13, ifndata
+ iwarp table 14, ifndata
+ iwindowtype table 15, ifndata
+
+ if (iwindowtype == 0) then
+ iwindow = gifnHanning
+ elseif (iwindowtype == 1) then
+ iwindow = gifnHamming
+ else
+ iwindow = gifnHalfSine
+ endif
+
+
+ if (iloop == 0 && iwarp == 0) then
+ p3 = itotalduration
+ if (iwarpmode == 0) then
+ p3 /= tab_i(7, ifndata)
+ endif
+ endif
+
+ if (iwarp == 1) then
+ if (iloop == 1) then
+ iduration = itotalduration
+ else
+ iduration = p3
+ endif
+
+ kdiv = gkseq_beattime / idivisions
+ as, aps syncphasor -(gkseq_beathz*idivisions), a(gkseq_beat)
+ ;ithresh = ((1 / sr) * ksmps) * 16
+ kt trigger k(as), 0.1, 0 ; was 0.005.. works?
+
+ ktime init 0
+ kpoint init giecp_controlitemnum
+ kcps init 1 / iduration
+ kpointend init table:i(giecp_controlitemnum+1, ifndata)
+
+ if (kt == 1) then
+ ktime = table:k(kpoint, ifndata)
+
+ if (kpoint + 1 < ftlen(ifndata)) then
+ kpointend = table:k(kpoint + 1, ifndata)
+ kpoint += 1
+ else
+ kpointend = iduration
+ kpoint = giecp_controlitemnum
+ endif
+ kcps = (kpointend - ktime) / kdiv
+ endif
+ atime, a_ syncphasor kcps, a(kt) ;a(gkseq_beat) ;aps
+
+ else
+ ktime init 0
+ atime phasor 1 / itotalduration
+ atime *= itotalduration
+ endif
+
+ ; repitch
+ if (iwarpmode == 0) then
+ if (iwarp == 1) then
+ aptime = (atime + ktime) * ftsr(ifnL)
+ else
+ aptime = atime * ftsr(ifnL) * kpitch ; * 0.5 ; why is 0.5 required here?
+ endif
+
+ aoutL table3 aptime, ifnL, 0
+ if (ifnR != 0) then
+ aoutR tablekt aptime, ifnR, 0
+ else
+ aoutR = aoutL
+ endif
+
+ ; texture
+ elseif (iwarpmode == 1) then
+ isradjust = ftsr(ifnL) / sr
+ aoutL sndwarp 1, (atime + ktime), a(kpitch) * isradjust, ifnL, 0, iwindowsize, irandwin, ioverlap, iwindow, 1
+ if (ifnR != 0) then
+ aoutR sndwarp 1, (atime + ktime), a(kpitch) * isradjust, ifnR, 0, iwindowsize, irandwin, ioverlap, iwindow, 1
+ else
+ aoutR = aoutL
+ endif
+
+ ; mincer
+ elseif (iwarpmode == 2) then
+ aoutL mincer atime + ktime, 1, kpitch, ifnL, kmincelock, ifftsize, 4
+ if (ifnR != 0) then
+ aoutR mincer atime + ktime, 1, kpitch, ifnR, kmincelock, ifftsize, 4
+ else
+ aoutR = aoutL
+ endif
+
+ ; pvs
+ elseif (iwarpmode == 3) then ; contentious benefit
+ ipvsbufL pvs_ifn2buffer ifnL, ifftsize, ifftsize/4, ifftsize, 2
+ ffoutL pvsbufread k(atime) + ktime, ipvsbufL
+ if (kpitch != 1) then
+ fscaleL pvscale ffoutL, kpitch
+ aoutL pvsynth fscaleL
+ else
+ aoutL pvsynth ffoutL
+ endif
+
+ if (ifnR != 0) then
+ ipvsbufR pvs_ifn2buffer ifnR, ifftsize, ifftsize/4, ifftsize, 2
+ ffoutR pvsbufread k(atime) + ktime, ipvsbufR
+ if (kpitch != 1) then
+ fscaleR pvscale ffoutR, kpitch
+ aoutR pvsynth fscaleR
+ else
+ aoutR pvsynth ffoutR
+ endif
+ else
+ ifnR = ifnL
+ endif
+ endif
+
+ aamp linseg 1, p3 * 0.9999, 1, p3 * 0.0001, 0
+
+ aoutL *= aamp * kamp
+ aoutR *= aamp * kamp
+ bus_mix(Sbus, aoutL, aoutR)
+ if (icbid > 0) then
+ kreleasing init 0
+ if (release:k() == 1 && kreleasing == 0) then
+ kreleasing = 1
+ schedulek("ecp_stopped", 0, 1, icbid)
+ endif
+ endif
+endin
+
+
+instr ecp_stopped
+ icbid = p4
+ io_sendstring("callback", sprintf("{\"cbid\": %d, \"status\": 0}", icbid))
+ turnoff
+endin
+
+
+#ifndef ECP_NORECORDING
+instr ecp_record_stop
+ icbid = p4
+ turnoff2 nstrnum("ecp_record") + (icbid / 1000000), 4, 1
+ turnoff
+endin
+
+
+instr ecp_record
+ icbid = p4
+ istereo = p5
+
+ p1 += icbid / 1000000
+ io_sendstring("callback", sprintf("{\"cbid\": %d, \"status\": 1}", icbid))
+
+ kbeats init 0
+ if (gkseq_beat == 1) then
+ kbeats += 1
+ endif
+
+ awritepos lphasor 1
+ ainL inch 1
+ tabw ainL, awritepos, giecp_recordbufferL
+ if (istereo == 1) then
+ ainR inch 2
+ tabw ainR, awritepos, giecp_recordbufferR
+ endif
+
+ kreleasing init 0
+ if (release:k() == 1 && kreleasing == 0) then
+ kreleasing = 1
+ schedulek "ecp_record_post", 0, 10, icbid, istereo, kbeats
+ endif
+endin
+
+
+instr ecp_record_scheduled_cancel
+ icbid = p4
+ turnoff2 nstrnum("ecp_record_scheduled") + (icbid / 1000000), 4, 1
+ turnoff
+endin
+
+instr ecp_record_scheduled
+ icbid = p4
+ istereo = p5
+ imode = p6 ; -1 = now, 0 = beat, 1 = bar , 2 = bargroup
+
+ p1 += icbid / 1000000
+ io_sendstring("callback", sprintf("{\"cbid\": %d, \"status\": 4}", icbid))
+
+ if ((imode == -1) || (imode == 0 && gkseq_beat == 1) || (imode == 1 && gkseq_bar_trig == 1) || (imode == 2 && gkseq_bargroup_trig == 1)) then
+ schedulek("ecp_record", 0, giecp_recordbufferduration, icbid, istereo)
+ turnoff
+ endif
+endin
+
+
+instr ecp_record_post
+ icbid = p4
+ istereo = p5
+ ibeats = p6
+
+ io_sendstring("callback", sprintf("{\"cbid\": %d, \"status\": 2}", icbid))
+
+ istart = 0 ;ksmps * 8
+ iduration = i(gkseq_beattime) * ibeats
+ ilen = iduration * sr
+ ifnL ftgen 0, 0, -ilen, -7, 0
+ ftslicei giecp_recordbufferL, ifnL, istart, ilen
+ if (istereo == 1) then
+ ifnR ftgen 0, 0, -ilen, -7, 0
+ ftslicei giecp_recordbufferR, ifnR, istart, ilen
+ endif
+ iclipindex = ecp_addclip("", ifnL, ifnR, ibeats, 4)
+
+ io_sendstring("callback", sprintf("{\"cbid\": %d, \"status\": 0}", icbid))
+
+ ; testing
+ if (gkseq_bar_trig == 1) then
+ schedulek "ecp_playback", 0, 100, iclipindex, "mxchan0"
+ turnoff
+ endif
+
+ ; turnoff
+endin
+#end
+
+#end
|