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
|
#ifndef UDO_MELSEQUENCINGPORT
#define UDO_MELSEQUENCINGPORT ##
/*
Extension to sequencing_melodic.udo which permits usage of k-rate frequency arrays
Slim excerpt for Partial Emergence
This file is part of the SONICS UDO collection by Richard Knight 2021
License: GPL-2.0-or-later
http://1bpm.net
*/
#include "sonics/sequencing_melodic.udo"
#include "sonics/wavetables.udo"
gimel_freqs ftgen 0, 0, -12, -7, 0 ; current notes: index 0 is the length
gimel_amps ftgen 0, 0, -12, -7, 0 ; current notes: index 0 is the length
gimel_portamento_beatratio init 0.5 ; portamento time as ratio of current beat time
gimel_linetype init 0 ; 0=pre-section, 1=post-section
/*
Automate a frequency/amp line
*/
instr _mel_linedraw
index = p4
ifreq = p5
iamp = p6
icurrentfreq table index, gimel_freqs
if (icurrentfreq == 0 && ifreq != 0) then
tablew ifreq, index, gimel_freqs
elseif (ifreq != 0 && icurrentfreq != ifreq) then
tablew line:k(icurrentfreq, p3, ifreq), index, gimel_freqs
endif
icurrentamp table index, gimel_amps
if (icurrentamp != iamp) then
tablew line:k(icurrentamp, p3, iamp), index, gimel_amps
endif
endin
instr _mel_linestep_inner
if (timeinstk() == 1) then
turnoff2 "_mel_linedraw", 0, 0
endif
if (table:i(1, gimel_next_notes) != 0) then
index = 0
while (index < table:i(0, gimel_next_notes)) do
event_i "i", "_mel_linedraw", 1/kr, p3, index, cpsmidinn(table:i(index + 1, gimel_next_notes)), 1
index += 1
od
while (index < ftlen(gimel_freqs)) do
event_i "i", "_mel_linedraw", 1/kr, p3, index, 0, 0
index += 1
od
endif
endin
instr _mel_linestep
icurrentduration mel_length
ilinetime = (i(gkseq_beattime) * gimel_portamento_beatratio)
if (gimel_linetype == 0) then
inextline = icurrentduration - ilinetime
else
inextline = icurrentduration
endif
event_i "i", "_mel_linestep_inner", inextline, ilinetime
turnoff
endin
/*
Portamento manager: respond to gkmel_section_change trigger by calling _mel_linestep instrument
*/
instr _mel_linemanager
; set initial freqs
index = 0
while (index < table:i(0, gimel_current_notes)) do
tablew cpsmidinn(table:i(index + 1, gimel_current_notes)), index, gimel_freqs
tablew 1, index, gimel_amps
index += 1
od
while (index < ftlen(gimel_freqs)) do
tablew 0, index, gimel_amps
index += 1
od
schedkwhen gkmel_section_change, 0, 1, "_mel_linestep", 0, 1
endin
schedule "_mel_linemanager", 0.1, 36000 ; notes not ready on 0
;alwayson "_mel_linemanager"
/*
Recursively create a chord to be used by mel_tune_portamento; internal use only
aout _mel_tune_chord_portamento kfreqmult, ifn, imaxmult, imult, index
aout chord output
kfreqmult frequency multiplier to apply to tuning
ifn wavetable to use
imaxmult multiples of harmonics to generate in tuning
imult internal multiplier for recursion
index internal index for recursion
*/
opcode _mel_tune_chord_portamento, a, kiipo
kfreqmult, ifn, imaxmult, imult, index xin
if (index + 1 > ftlen(gimel_amps)) then
index = 0
imult += 1
endif
aout = oscil(table:k(index, gimel_amps), kfreqmult * table:k(index, gimel_freqs) * pow:k(2, imult), ifn) * 0.1
; recursion for all chord parts
if (imult <= imaxmult) then
aout += _mel_tune_chord_portamento(kfreqmult, ifn, imaxmult, imult, index + 1)
endif
xout aout
endop
/*
Stereo tuning to current melodic sequencer notes
aoutL, aoutR mel_tune ainL, ainR, ifn, imult [, ifftrate, ifftdiv]
aoutL, aoutR output audio
ainL, ainR input audio
ifn wavetable to use
imaxmult multiples of harmonics to generate in tuning (defaults to 4)
ifftrate fft size, defaults to config default
ifftdiv fft window division factor (eg 4, 8, 16), defaults to config default
kfreqmult frequency multiplier to apply to tuning
*/
opcode mel_tune_portamento, aa, aaooooP
aL, aR, ifn, imaxmult, ifftrate, ifftdiv, kfreqmult xin
ifn = (ifn == 0) ? gifnSine : ifn
imaxmult = (imaxmult == 0) ? 4 : imaxmult
ifftrate = (ifftrate == 0) ? 512 : ifftrate
ifftdiv = (ifftdiv == 0) ? 4 : ifftdiv
fmods pvsanal _mel_tune_chord_portamento(kfreqmult, ifn, imaxmult), ifftrate, ifftrate/ifftdiv, ifftrate, 1
fL1 pvsanal aL, ifftrate, ifftrate/ifftdiv, ifftrate, 1
fR1 pvsanal aR, ifftrate, ifftrate/ifftdiv, ifftrate, 1
fL2 pvsmorph fL1, fmods, 0, 1
fR2 pvsmorph fR1, fmods, 0, 1
aL1 pvsynth fL2
aR1 pvsynth fR2
idel = (ifftrate+2)/sr
aL1 balance aL1, delay(aL, idel)
aR1 balance aR1, delay(aR, idel)
xout aL1, aR1
endop
#end
|