aboutsummaryrefslogtreecommitdiff
path: root/site/udo/transient_detect.udo
blob: 4acf1d3ef021605e8e1f35c7d74183f8dc199299 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#ifndef UDO_TRANSIENTDETECT
#define UDO_TRANSIENTDETECT ##
/*
	Transient detection

	This file is part of the SONICS UDO collection by Richard Knight 2021
		License: GPL-2.0-or-later
		http://1bpm.net
*/

/*
        Internal transient detection base
*/
opcode _transientdetect, kk,kikkki
	kin, iresponse, ktthresh, klowThresh, kdecThresh, idoubleLimit xin
	kinDel delayk kin, iresponse / 1000
	ktrig = ((kin > kinDel + ktthresh) ? 1 : 0)
	klowGate = (kin < klowThresh ? 0 : 1)
	ktrig = ktrig * klowGate
	ktransLev init 0
	ktransLev samphold kin, 1-ktrig
	kreGate init 1
	ktrig = ktrig * kreGate
	kmaxAmp init -99999
	kmaxAmp max kmaxAmp, kin
	kdiff = kmaxAmp-kin
	kreGate limit kreGate-ktrig, 0, 1
	kreGate = (kdiff > kdecThresh ? 1 : kreGate)
	kmaxAmp = (kreGate == 1 ? -99999 : kmaxAmp)
	xout ktrig, kdiff
endop



opcode transientdetect, k, akkiikkk
	ain, kattack, krelease, iresponse, idoublelimit, ktthresh, klowthresh, kdecthresh xin
	afollow follow2 ain, kattack, krelease
	kfollow downsamp afollow
	kfollowdb = dbfsamp(kfollow)
	ktrig, kdiff _transientdetect kfollowdb, iresponse, ktthresh, klowthresh, kdecthresh, idoublelimit
	xout ktrig
endop

/*
    Default transient detection
	ktrigger transientdetect ainput

	ktrigger	fires when a transient has been detected
	ainput		the audio signal to track
*/
opcode transientdetect, k, a
	ain xin
	kattack init 0.05
	krelease init 0.06
	iresponse = 10
	ktthresh = 9
	klowthresh = -50
	idoublelimit = 0.1
	kdecthresh = 6
	ktrig transientdetect ain, kattack, krelease, iresponse, idoublelimit, ktthresh, klowthresh, kdecthresh
	xout ktrig
endop

/*

opcode transientdetect, k, a
	ain xin
	kattack init 0.05
	krelease init 0.06
	afollow follow2 ain, kattack, krelease
	kfollow downsamp afollow
	kfollowdb = dbfsamp(kfollow)
	iresponse = 10
	ktthresh = 9
	klowthresh = -50
	idoublelimit = 0.1
	kdecthresh = 6
	ktrig, kdiff _transientdetect kfollowdb, iresponse, ktthresh, klowthresh, kdecthresh, idoublelimit
	xout ktrig
endop

*/

/*
        Detect transients in audio ftable; count or output to ftable

        p4	ftable to read sound from
		p5	instrument name to invoke when complete, ftable contaqining transients is passed as p4
		p6	0 = stage 1, count and recall; 1 = stage 2, write to ftable
		p7	number of transients for ftable initialisation as used with stage 2
*/
instr _transientdetect_tofn_inner
	ifnsound = p4
	SonComplete = p5
	istate = p6
	itransientnum = p7

	if (istate == 0) then
		ifntransients = -1
	else
		ifntransients ftgen 0, 0, itransientnum, 7, 0
	endif


	kdone init 0
	ktransientnum init 0
	ktimek timeinstk
	if (ktimek == 1) then
		inputduration = ftlen(ifnsound) / ftsr(ifnsound)
		kcycles = inputduration * kr
		kcount init 0
		while (kcount < kcycles) do
			if (ftchnls(ifnsound) == 1) then
				asound loscil 1, 1, ifnsound, 1
			else
				aL, aR loscil 1, 1, ifnsound, 1
				asound = (aL + aR) / 2
			endif
			;ktransient, kdiff _transientdetectinner asound
			ktransient transientdetect asound
			if (ktransient == 1) then
				if (ifntransients != -1) then
					tablew (inputduration / kcycles) * kcount, ktransientnum, ifntransients
				endif
				ktransientnum += 1
			endif
			kcount += 1
		od
	else
		if (istate == 0) then
			if (ktransientnum == 0) then
				schedulek(SonComplete, 0, 3600, -1)
			else
				schedulek(p1, 0, 1, ifnsound, SonComplete, 1, ktransientnum)
			endif
		else
				schedulek(SonComplete, 0, 3600, ifntransients)
		endif
		turnoff
	endif
endin


opcode transientdetect_tofn, 0, iS
	ifn, SonComplete xin
	schedule("_transientdetect_tofn_inner", 0, 600, ifn, SonComplete, 0, 0)
endop


opcode randomtransient, ii, i
	ifntransients xin
	iftlen = ftlen(ifntransients)
	if (iftlen < 2) then
		istart = tab_i(0, ifntransients) 
		ilen = 0.1
	else
		istartindex = round(random(0, iftlen - 2))
		istart = tab_i(istartindex, ifntransients) 
		iend = tab_i(istartindex + 1, ifntransients)
		ilen = iend - istart
	endif

	if (ilen > 1) then
		ilen = 1
	endif
	xout istart, ilen
endop

/*
	By Brandtsegg, I think; tweaked by RK
*/
opcode onsetdetect, k, aiiiiii
    ain, iMinFreq, iMaxFreq, iAboveMed, iOffset, iMinSec, iMedLen xin
    ifftsize = 1024
    iIndexStart limit int(iMinFreq*(ifftsize/sr))*2,0,sr/2
    iIndexEnd limit int(iMaxFreq*(ifftsize/sr))*2,0,sr/2
    fsrc pvsanal ain,ifftsize,ifftsize/4,ifftsize,1
    kArr[] init ifftsize+2
    kflag pvs2array kArr, fsrc
    ksumold init 0
    kMedIndex init 0
    kMedSum init 0
    kMedian[] init iMedLen
    kMinDist init 0
    iMinDist = iMinSec*(sr/ksmps)
    kMinDist limit kMinDist-1,0,100000

    if changed(kflag) == 1 && kMinDist == 0 then
        ksum = 0
        kIndex = iIndexStart

        until kIndex = iIndexEnd do
            ksum = ksum+kArr[kIndex]
            kIndex += 2
        od

        kFLUX = ksum-ksumold
        ksumold = ksum
        kOnset = 0

        if kFLUX > (kMedSum*iAboveMed)+iOffset then
            kOnset = 1
            kMinDist = iMinDist
        endif

        kMedian[kMedIndex] = (kFLUX>=0?kFLUX:0)
        kMedSum = sumarray(kMedian)/iMedLen
        kMedIndex = (kMedIndex+1)%iMedLen

    endif

    xout changed(kOnset)==1 && kOnset==1 ? 1 : 0

endop

#end