; PvsRecPlay.csd
; Written by Iain McCurdy, 2012
form caption("PVS Rec/Play") size(300, 550), pluginid("pvrp")
groupbox bounds( 0, 0,300, 95), text("Transport")
label bounds( 10, 75, 70, 14), text("Record")
label bounds( 80, 75, 70, 14), text("Pause")
label bounds(150, 75, 70, 14), text("Play Loop")
label bounds(220, 75, 70, 14), text("Play Once")
checkbox bounds( 10, 25, 70, 50), channel("Record"), value(0), shape("square"), colour("red")
checkbox bounds( 80, 25, 70, 50), channel("Pause"), value(0), shape("square"), colour("Blue")
checkbox bounds(150, 25, 70, 50), channel("PlayLoop"), value(0), shape("square")
checkbox bounds(220, 25, 70, 50), channel("PlayOnce"), value(0), shape("square"), colour("yellow")
hslider bounds( 0, 95, 300,50), channel("Speed"), range(.125, 4.00, 1, .5) ;, text("Speed") ;.5 = exponential fashion
label bounds(100, 135, 100,13), text("Speed") , align(centre)
hslider bounds( 0, 145, 300,50), channel("Pitch"), range(0.25, 4.00, 1) ;, text("Pitch")
label bounds(100, 185, 100,13), text("Pitch") , align(centre)
hslider bounds( 0, 195, 300,50), channel("LoopBeg"), range(0, 1, 0) ;, text("Loop Begin")
label bounds(100, 235, 100,13), text("Loop Begin") , align(centre)
hslider bounds( 0, 245, 300,50), channel("LoopEnd"), range(0, 1, 1) ;, text("Loop End")
label bounds(100, 285, 100,13), text("Loop End") , align(centre)
hslider bounds( 0, 295, 150,50), channel("Attack"), range(.01, 1, .2) ;, text("Attack Time")
label bounds( 25, 335, 100,13), text("Attack Time") , align(centre)
hslider bounds(150, 295, 150,50), channel("Release"), range(.01, 1, .2) ;, text("Release Time")
label bounds(175, 335, 100,13), text("Release Time") , align(centre)
hslider bounds( 0, 345, 300,50), channel("InGain"), range(0, 1, 1) ;, text("Input Gain")
label bounds(100, 385, 100,13), text("Input Gain") , align(centre)
hslider bounds( 0, 395, 300,50), channel("OutGain"), range(0, 1, 1) ;, text("Output Gain")
label bounds(100, 435, 100,13), text("Output Gain") , align(centre)
keyboard bounds(8, 460, 285, 80)
;-d -n
-dm0 -n -+rtmidi=null -M0 ;flag copati da LiveLooper.
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1
massign 0, 3
;Author: Iain McCurdy (2012)
;***PER ATTIVARE REGISTRAZIONE STEREO RIPRISTINA RIGHE COMMENTATE CON ***
gistorageL ftgen 0,0,1048576,-7,0 ;AUDIO DATA STORAGE SPACE (ABOUT 23 SECONDS)
;gistorageR ftgen 0,0,1048576,-7,0 ;AUDIO DATA STORAGE SPACE (ABOUT 23 SECONDS) ;***SE LA REGISTRAZIONE è MONO QUESTA RIGA NON SERVE
gkRecDur init 0 ;DURATION OF THE MOST RECENTLY RECORDED BUFFER
gibuflen init 60 ;PVS BUFFER LENGTH
instr 1 ;READ IN WIDGETS AND START AND STOP THE VARIOUS RECORDING AND PLAYBACK INSTRUMENTS
gitablelen = ftlen(gistorageL) ;DERIVE TABLE LENGTH
gkRecord chnget "Record" ;READ IN CABBAGE WIDGET CHANNELS
gkPause chnget "Pause"
gkPlayLoop chnget "PlayLoop"
gkPlayOnce chnget "PlayOnce"
gkPlayOnceTrig changed gkPlayOnce
gkSpeed chnget "Speed"
gkPitch chnget "Pitch"
gkLoopBeg chnget "LoopBeg"
gkLoopEnd chnget "LoopEnd"
gkInGain chnget "InGain"
gkOutGain chnget "OutGain"
gkAtkTime chnget "Attack"
gkRelTime chnget "Release"
;=============================feature to transform 'k' to 'i', valid for 'linsegr'
giAtkTime init i(gkAtkTime) ;trasforma variabile 'k' in variabile 'i' per essere compatibile con 'linsegr', che accetta solo 'i'
giRelTime init i(gkRelTime)
kRelChange changed gkAtkTime, gkRelTime
;printk2 kRelChange
if kRelChange = 1 then ;se muovi lo slider
reinit reset2
reset2:
giAtkTime = i(gkAtkTime)
giRelTime = i(gkRelTime) ;aggiorna i valori
;print giRelTime
rireturn
endif
;=============================
/*
;SOSTITUITO DAL 'DEFINE' SEGUENTE, PRESO DA TabRecFx.csd
#define TURN_ON(NAME)
#
i$NAME nstrnum "$NAME"
kOnTrig$NAME trigger gk$NAME,0.5,0
if kOnTrig$NAME==1 then ;IF BUTTON IS TURNED ON...
turnoff2 i$NAME,0,giRelTime ;UTILE NEL CASO IN CUI SI PREMA IL PLAY MENTRE ANCORA è IN ESECUZIONE IL RELEASE, PER NON FAR RIMANERE 'INCANTATO' IL BOTTONE
event "i",i$NAME,0,3600
endif
#
$TURN_ON(Record)
$TURN_ON(PlayOnce)
$TURN_ON(PlayLoop)
*/
;ALTERNATIVA A 'DEFINE'
#define TURN_ON_OFF(NAME) ;defines a macro with arguments. macro per accendere e spegnere gli strumenti: 'Record', 'PlayOnce', 'PlayLoop'
# ;l'argomento è 'NAME'
i$NAME nstrnum "$NAME" ;Returns the number of a named instrument. $NAME può essere lo strumento "Record' o 'PlayOnce' o 'PlayLoop', come stabilito sotto
;>>>>>>>>>>>>>>>> i$NAME cambia ad 'i' time, vedere oltre l'uso degli opcode 'event' e 'turnoff2' <<<<<<<<<<<<<<<<<<<<<<
;serve ad accendere e spegnere gli strumenti 'Record', 'PlayOnce', 'PlayLoop'
kOnTrig$NAME trigger gk$NAME,0.5,0 ;Informs when a krate signal crosses a threshold: ksig, kthreshold, kmode. Se è maggiore di .5 (kmode=0) o se è minore di .5 (kmode = 1)
kOffTrig$NAME trigger gk$NAME,0.5,1 ;>>>>>>>>>>>>>>>>>>>> gk$NAME sarà secondo i casi: gkRecord o gkPlayOnce o gkPlayLoop <<<<<<<<<<<<<<<<<<<<<
if kOnTrig$NAME==1 then ;IF BUTTON IS TURNED ON...
turnoff2 i$NAME,0,0 ;UTILE NEL CASO IN CUI SI PREMA IL PLAY MENTRE ANCORA è IN ESECUZIONE IL RELEASE, PER NON FAR RIMANERE 'INCANTATO' IL BOTTONE
event "i",i$NAME,0,3600 ;Generates a score event from an instrument. event_i "scorechar", iinsnum, idelay, idur, [, ip4] [, ip5] [, ...]
elseif kOffTrig$NAME==1 then ;IF BUTTON IS TURNED ON...
turnoff2 i$NAME,0,giRelTime ;spegne lo strumento generato da 'event', tempo di rilascio definito in gkRelTime
;PERCHE' c'era una VIRGOLA DOPO turnoff2 e funzionava lo stesso???
endif
#
$TURN_ON_OFF(Record) ;applica la stessa macro con tre diversi bottoni (nomi dei canali)
$TURN_ON_OFF(PlayOnce)
$TURN_ON_OFF(PlayLoop)
endin
instr Record
if gkRecord==0 then ;IF BUTTON IS TURNED ON...
turnoff
endif
if gkPause=1 goto SKIP_RECORD ;IF PAUSE BUTTON IS ACTIVATED TEMPORARILY SKIP RECORDING PROCESS
ainL,ainR ins ;READ AUDIO FROM LIVE INPUT CHANNEL 1
;MACRO THAT DEFINES THE CODED NEEDED TO RECORD A SINGLE CHANNEL PVS BUFFER
#define REC_BUF(CHAN)
#
iFFTsize = 1024
ioverlap = 256
iwinsize = 1024
iwintype = 1
;kPhOffset = 0
f_anal$CHAN pvsanal ain$CHAN, iFFTsize, ioverlap, iwinsize, iwintype ;ANALYSE THE LEFT CHANNEL AUDIO. OUTPUT AN F-SIGNAL.
ibuf$CHAN,ktime pvsbuffer f_anal$CHAN, gibuflen ;BUFFER FSIG
gkhandle$CHAN init ibuf$CHAN ;INITIALISE HANDLE TO BUFFER
#
;EXPAND BUFFER TWICE, ONCE FOR EACH STEREO CHANNEL
$REC_BUF(L)
;$REC_BUF(R) ;***NEL CASO DI REGISTRAZIONE MONO QUESTA RIGA NON SERVE
gkRecDur timeinsts ;DURATION OF CURRENT RECORDING
if gkRecDur>=gibuflen then ;IF BUFFER IS FULL (I.E. DO NOT OVERWRITE THE BEGINNING OF THE BUFFER
turnoff ;TURN OFF THIS INSTRUMENT
endif ;ENDO OF THIS CONDITIONAL BRANCH
SKIP_RECORD: ;JUMP TO HERE WHEN 'PAUSE' BUTTON IS ACTIVE
endin
instr PlayLoop
;if gkPlayLoop==0 then ;IF BUTTON IS TURNED ON...
;turnoff
;endif
if gkPlayLoop==0 then ;IF 'PLAY LOOPED' BUTTON IS INACTIVE...
turnoff2 "PlayLoop",0,giRelTime ;TURN THIS INSTRUMENT OFF
endif ;END OF THIS CONDITIONAL BRANCH
if gkPause=1 goto SKIP_PLAY_LOOP ;IF PAUSE BUTTON IS ACTIVATED SKIP PLAYBACK CODE
;kporttime linseg 0,0.001,0.05 ;PORTAMENTO TIME RAMPS UP RAPIDLY TO A HELD VALUE
kLoopBeg = gkLoopBeg
kLoopEnd = gkLoopEnd
;portk fa imballare il processo quando kLoopBeg e kLoopEnd hanno valori uguali!!!!!! Oltre tutto sembra che non serva a nulla!!!!!!!!
;kLoopBeg portk gkLoopBeg, kporttime ;APPLY PORTAMENTO SMOOTHING TO CHANGES OF LOOP BEGIN SLIDER
;kLoopEnd portk gkLoopEnd, kporttime ;APPLY PORTAMENTO SMOOTHING TO CHANGES OF LOOP END SLIDER
kLoopBeg = kLoopBeg * gkRecDur ;RESCALE gkLoopBeg (RANGE 0-1) TO BE WITHIN THE RANGE 0-FILE_LENGTH.
kLoopEnd = kLoopEnd * gkRecDur ;RESCALE gkLoopEnd (RANGE 0-1) TO BE WITHIN THE RANGE 0-FILE_LENGTH.
kLoopLen = abs(kLoopEnd - kLoopBeg) ;DERIVE LOOP LENGTH FROM LOOP START AND END POINTS
kPlayPhasFrq divz gkSpeed, kLoopLen, 0.00001 ;SAFELY DIVIDE, PROVIDING ALTERNATIVE VALUE IN CASE DENOMINATOR IS ZERO
kPlayNdx phasor kPlayPhasFrq ;DEFINE PHASOR POINTER FOR BUFFER READ INDEX
;kLoopBeg = (kLoopBeg < kLoopEnd ? kLoopBeg : kLoopEnd) ;CHECK IF LOOP-BEGINNING AND LOOP-END SLIDERS HAVE BEEN REVERSED
;printk .2, kPlayNdx
if kLoopBeg < kLoopEnd then
kPlayNdx = (kPlayNdx*kLoopLen) + kLoopBeg ;RESCALE INDEX POINTER ACCORDING TO LOOP LENGTH AND LOOP BEGINING
elseif kLoopBeg > kLoopEnd then
kPlayNdx = kLoopBeg-(kPlayNdx*kLoopLen) ;INVERTE LA DIREZIONE
else
kPlayNdx = kLoopBeg
endif ;...IN TAL MODO SPEGNENDO E RIACCENDENDO IL BOTTONE LA LETTURA RIPARTE.
printk .2, kPlayNdx
f_bufL pvsbufread kPlayNdx , gkhandleL ;READ BUFFER
f_scaleL pvscale f_bufL, gkPitch ;RESCALE FREQUENCIES
aL pvsynth f_scaleL ;RESYNTHESIZE THE f-SIGNAL AS AN AUDIO SIGNAL
;***SE LA REGISTRAZIONE è MONO LE TRE RIGHE SUCCESSIVE NON SERVONO
;f_bufR pvsbufread kPlayNdx , gkhandleR ;READ BUFFER - SE VUOI USARE INGRESSO STEREO RIPRISTINA gkhandleR!!!!!!
;f_scaleR pvscale f_bufR, gkPitch ;RESCALE FREQUENCIES
;aR pvsynth f_scaleR ;RESYNTHESIZE THE f-SIGNAL AS AN AUDIO SIGNAL
kEnv linsegr 0, giAtkTime, 1, giRelTime, 0 ;inviluppo globale. Tempo di rilascio in accordo con turnoff2
;***SE LA REGISTRAZIONE è MONO SCRIVERE ALL'USCITA DUE VOLTE aL, ALTRIMENTI aL POI aR
outs aL*gkOutGain*kEnv,aL*gkOutGain*kEnv ;SEND AUDIO TO OUTPUTS
SKIP_PLAY_LOOP: ;JUMP TO HERE WHEN 'PAUSE' BUTTON IS ACTIVE
endin
instr PlayOnce
;if gkPlayOnce==0 then ;IF BUTTON IS TURNED ON...
;turnoff ;2 "PlayOnce", 0, giRelTime
;endif
giRecDur = i(gkRecDur)
print giRecDur
if gkPause=1 goto SKIP_PLAY_ONCE ;IF PAUSE BUTTON IS ACTIVATED SKIP PLAYBACK
kPlayOnceNdx init 0 ;INITIALISE PLAYBACK POINTER
;gkLoopBeg = gkSpeed >= 0? gkLoopBeg:gkLoopEnd
;gkLoopEnd = gkSpeed >= 0? gkLoopEnd:gkLoopBeg
kLoopBeg = gkLoopBeg * giRecDur ;RESCALE gkLoopBeg (RANGE 0-1) TO BE WITHIN THE RANGE 0-FILE_LENGTH. 'BEGIN' IN SECONDI
kLoopEnd = gkLoopEnd * giRecDur ;RESCALE gkLoopEnd (RANGE 0-1) TO BE WITHIN THE RANGE 0-FILE_LENGTH. 'END' IN SECONDI
kLoopDur = abs(kLoopBeg-kLoopEnd)
;printk .2,kLoopDur
;=============================feature to transform 'k' to 'i', valid for 'line' of kPlayOnceNdx
kNdxLine changed kLoopDur, gkSpeed
if kNdxLine = 1 then ;se muovi lo slider
reinit reset22
reset22:
iLoopBeg = i(kLoopBeg)
iLoopEnd = i(kLoopEnd) ;aggiorna i valori
iSpeed = i(gkSpeed)
iLoopDur = i(kLoopDur)/iSpeed
;rireturn
endif
;=============================
kPlayOnceNdx line iLoopBeg,iLoopDur,iLoopEnd
printk .2, kPlayOnceNdx
if iLoopBeg < iLoopEnd && kPlayOnceNdx > iLoopEnd then
turnoff
endif
if iLoopBeg > iLoopEnd && kPlayOnceNdx < iLoopEnd then
turnoff
endif
;printk .2, kPlayOnceNdx
f_bufL pvsbufread kPlayOnceNdx , gkhandleL ;READ BUFFER
f_scaleL pvscale f_bufL, gkPitch ;RESCALE FREQUENCIES
aL pvsynth f_scaleL ;RESYNTHESIZE THE f-SIGNAL AS AN AUDIO SIGNAL
;***SE LA REGISTRAZIONE è MONO LE TRE RIGHE SUCCESSIVE NON SERVONO
;f_bufR pvsbufread kPlayOnceNdx , gkhandleR ;READ BUFFER - SE VUOI USARE INGRESSO STEREO RIPRISTINA gkhandleR!!!!!!
;f_scaleR pvscale f_bufR, gkPitch ;RESCALE FREQUENCIES
;aR pvsynth f_scaleR ;RESYNTHESIZE THE f-SIGNAL AS AN AUDIO SIGNAL
kEnv linsegr 0, giAtkTime, 1, giRelTime, 0 ;inviluppo globale. Tempo di rilascio in accordo con turnoff2
;***SE LA REGISTRAZIONE è MONO SCRIVERE ALL'USCITA DUE VOLTE aL, ALTRIMENTI aL POI aR
outs aL*gkOutGain*kEnv,aL*gkOutGain*kEnv ;SEND AUDIO TO OUTPUT
;else
; turnoff
;endif ;END OF CONDITIONAL BRANCH
SKIP_PLAY_ONCE:
krelease release
if krelease==1 then
chnset 1-krelease,"PlayOnce"
endif
endin
instr 3 ; PLayMidi, molto simile allo strumento 'PlayLoop'
kpitch = cpsmidi()/cpsmidinn(60) ; DERIVE RATIO BASED ON NOTE NUMBER 60 AS THE POINT OF UNISON (IE. RATIO=1)
ival ampmidi 1
;if gkPlayLoop==0 then ;IF BUTTON IS TURNED ON...
;turnoff
;endif
;if gkPlayLoop==0 then ;IF 'PLAY LOOPED' BUTTON IS INACTIVE...
;turnoff ;TURN THIS INSTRUMENT OFF
;endif ;END OF THIS CONDITIONAL BRANCH
if gkPause=1 goto SKIP_PLAY_LOOP ;IF PAUSE BUTTON IS ACTIVATED SKIP PLAYBACK CODE
;kporttime linseg 0,0.001,0.05 ;PORTAMENTO TIME RAMPS UP RAPIDLY TO A HELD VALUE
kLoopBeg = gkLoopBeg
kLoopEnd = gkLoopEnd
;portk fa imballare il processo quando kLoopBeg e kLoopEnd hanno valori uguali!!!!!! Oltre tutto sembra che non serva a nulla!!!!!!!!
;kLoopBeg portk gkLoopBeg, kporttime ;APPLY PORTAMENTO SMOOTHING TO CHANGES OF LOOP BEGIN SLIDER
;kLoopEnd portk gkLoopEnd, kporttime ;APPLY PORTAMENTO SMOOTHING TO CHANGES OF LOOP END SLIDER
kLoopBeg = kLoopBeg * gkRecDur ;RESCALE gkLoopBeg (RANGE 0-1) TO BE WITHIN THE RANGE 0-FILE_LENGTH.
kLoopEnd = kLoopEnd * gkRecDur ;RESCALE gkLoopEnd (RANGE 0-1) TO BE WITHIN THE RANGE 0-FILE_LENGTH.
kLoopLen = abs(kLoopEnd - kLoopBeg) ;DERIVE LOOP LENGTH FROM LOOP START AND END POINTS
kPlayPhasFrq divz gkSpeed, kLoopLen, 0.00001 ;SAFELY DIVIDE, PROVIDING ALTERNATIVE VALUE IN CASE DENOMINATOR IS ZERO
kPlayNdx phasor kPlayPhasFrq ;DEFINE PHASOR POINTER FOR BUFFER READ INDEX
;kLoopBeg = (kLoopBeg < kLoopEnd ? kLoopBeg : kLoopEnd) ;CHECK IF LOOP-BEGINNING AND LOOP-END SLIDERS HAVE BEEN REVERSED
if kLoopBeg < kLoopEnd then
kPlayNdx = (kPlayNdx*kLoopLen) + kLoopBeg ;RESCALE INDEX POINTER ACCORDING TO LOOP LENGTH AND LOOP BEGINING
elseif kLoopBeg > kLoopEnd then
kPlayNdx = kLoopBeg-(kPlayNdx*kLoopLen) ;INVERTE LA DIREZIONE
else
kLoopEnd = kLoopEnd-(kr/sr) ;EVITA CHE SI IMBALLI COMPLETAMENTE NEL CASO CHE I DUE VALORI COINCIDANO...
endif ;...IN TAL MODO SPEGNENDO E RIACCENDENDO IL BOTTONE LA LETTURA RIPARTE.
f_bufL pvsbufread kPlayNdx , gkhandleL ;READ BUFFER
f_scaleL pvscale f_bufL, gkPitch*kpitch ;RESCALE FREQUENCIES
aL pvsynth f_scaleL ;RESYNTHESIZE THE f-SIGNAL AS AN AUDIO SIGNAL
;***SE LA REGISTRAZIONE è MONO LE TRE RIGHE SUCCESSIVE NON SERVONO
;f_bufR pvsbufread kPlayNdx , gkhandleR ;READ BUFFER - SE VUOI USARE INGRESSO STEREO RIPRISTINA gkhandleR!!!!!!
;f_scaleR pvscale f_bufR, gkPitch*kpitch ;RESCALE FREQUENCIES
;aR pvsynth f_scaleR ;RESYNTHESIZE THE f-SIGNAL AS AN AUDIO SIGNAL
kEnv linsegr 0, giAtkTime, ival, giRelTime, 0 ;inviluppo globale. Tempo di rilascio in accordo con turnoff2
;***SE LA REGISTRAZIONE è MONO SCRIVERE ALL'USCITA DUE VOLTE aL, ALTRIMENTI aL POI aR
outs aL*gkOutGain*kEnv,aL*gkOutGain*kEnv ;SEND AUDIO TO OUTPUTS
SKIP_PLAY_LOOP: ;JUMP TO HERE WHEN 'PAUSE' BUTTON IS ACTIVE
endin
i 1 0 [3600*24*7]