aboutsummaryrefslogtreecommitdiff
path: root/sonics/sequencing_melodic_portamento.udo
blob: 208919dc453568dba7780aff18e123327549a5e0 (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
#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/__config__.udo"				; using fftsize for tuning
#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) ? giFFTsize : ifftrate
	ifftdiv = (ifftdiv == 0) ? giFFTwinFactor : 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