aboutsummaryrefslogtreecommitdiff
path: root/site/udo/sound_melsys.udo
blob: 588f137fece1722aa38ae2bbf3fca79db992601e (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
#ifndef UDO_MELSYS
#define UDO_MELSYS ##

/*
	Melodic sampler system
	
	Typical external usage should only refer to 
		mel_playnote
		mel_getcollection


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

*/



#include "sound_db.udo"
#include "pgdb.udo"
#include "host_tools.udo"
#include "pvs_tools.udo"
#include "bussing.udo"



opcode _mel_loadobject, i[][], S[][]
	Sres[][] xin
	imelmap[][] init 128, 16
	index = 0
	while (index < lenarray(Sres)) do
		ifileid strtod Sres[index][0]
		ichannels strtod Sres[index][2]
		iduration strtod Sres[index][3]
		inote strtod Sres[index][4]
		
		if (imelmap[inote][0] == 0) then
			imelmap[inote][0] = 1
		endif
		imelmap[inote][imelmap[inote][0]] _rdb_loadsound ifileid, ichannels, iduration, Sres[index][1]
		imelmap[inote][0] = imelmap[inote][0] + 1	; first index keeps track of length

		index += 1
	od
	xout imelmap
endop




/*
    Get soundcollection with basic analysis information
    isounds[][] 	getcollection ScollectionName

    isounds[][]		soundcollection object 
    ScollectionName the name of the filecollection in the database
*/
opcode mel_getcollection, i[][], S
	Scollection xin
	Sbase = {{select file_id, f_localpath(%d, path), channels, duration, note
		from svw.analysis_basic_collectionnorm a
		join filecollection fc on fc.id = a.filecollection_id
		join filecollectiontype fct on fct.id = fc.type_id
		where fc.name = '%s'
		and fct.name = 'melsys'
	}}
	Squery sprintf Sbase, gihost_type, Scollection
	Sres[][] dbarray gidb, Squery
	idata[][] _mel_loadobject Sres
	xout idata
endop


/*
	Get all melodic soundcollection names
	Scollections[] mel_listcollections

	Scollections[] 	list of soundcollections
*/
opcode mel_listcollections, S[], 0
	Sres[][] dbarray gidb, "select distinct fc.name from filecollection fc join filecollectiontype fct on fct.id = fc.type_id where fct.name = 'melsys'"
	ilen = lenarray(Sres)
	Scollections[] init ilen
	index = 0
	while (index < ilen) do
		Scollections[index] = Sres[index][0]
		index += 1
	od
	xout Scollections
endop


/*
	Get nearest note and a ratio to alter to specific note
*/
opcode _mel_getnearestnote, ii, ii[][]
	inote, imelmap[][] xin
	iratio = 0
	inearest = -1
	idistance = 999
	index = 0
	while (index < 128) do
		if (imelmap[index][0] > 0) then
			if (inote > index) then
				imeasure = inote - index
				if (imeasure < idistance) then
					idistance = imeasure
					inearest = index
				endif
			elseif (inote < index ) then
				imeasure = index - inote
				if (imeasure < idistance) then
					idistance = imeasure
					inearest = index
				endif
			else 
				idistance = 0
				inearest = inote
				goto output
			endif
		endif
		index += 1
	od
	iratio = cpsmidinn(inote) / cpsmidinn(inearest) 
output:
	isoundindex = imelmap[inearest][int(random(1, imelmap[inearest][0]))]
	xout isoundindex, iratio
endop


opcode mel_getrandnote, ii, ii[][]
	inote, imelmap[][] xin
	iout = -1
	if (imelmap[inote][0] > 0) then
		index = int(random(1, imelmap[inote][0]))
		iout = imelmap[inote][index]
		iratio = 1
	else
		iout, iratio _mel_getnearestnote inote, imelmap
	endif
	xout iout, iratio
endop



/*


*/
opcode _mel_playsound, 0, iSppooooo
	index, Sbus, iamp, ipitchratio, iwhen, iusepvs, ikeepformant, ifadein, idurationoverride xin
	Scoreline = sprintf("i\"mel_player_default\" %f 1 \"%s\" %f %f %f %d %d %d %f", iwhen, Sbus, index, iamp, ipitchratio, iusepvs, ikeepformant, ifadein, idurationoverride)
	scoreline_i Scoreline
endop


opcode mel_playnote, 0, i[][]iSpooooo
	imelmap[][], inote, Sbus, iamp, iwhen, idurationoverride, iusepvs, ikeepformant, ifadein xin
	isoundindex, ipitchratio mel_getrandnote inote, imelmap
	_mel_playsound isoundindex, Sbus, iamp, ipitchratio, iwhen, iusepvs, ikeepformant, ifadein, idurationoverride
endop




instr mel_player_default
	Sbus = p4
	isoundindex = p5
	iamp = p6
	ipitchratio = p7
	iusepvs = p8
	ikeepformant = p9
	ifadein = p10
	idurationoverride = p11
	isound[] = get_sound(isoundindex)
	
	if (idurationoverride == 0) then
		p3 = isound[3] ; set duration
	else
		p3 = idurationoverride
	endif

	
	if (iusepvs == 1) then
		iloscilratio = 1
	else
		iloscilratio = ipitchratio
	endif

	if (isound[2] == 1) then ; check channels
		aL loscil iamp, iloscilratio, isound[0], 1
		if (iusepvs == 1) then
			aL pvscaler aL, ipitchratio, ikeepformant
		endif
		aR = aL
	else
		aL, aR loscil iamp, iloscilratio, isound[0], 1
		if (iusepvs == 1) then
			aL pvscaler aL, ipitchratio, ikeepformant
			aR pvscaler aR, ipitchratio, ikeepformant
		endif
	endif

	if (ifadein == 1) then
		kenv linseg 0, p3*0.4, 1, p3*0.5, 1, p3*0.1, 0
	else
		kenv linseg 1, p3*0.9, 1, p3*0.1, 0
	endif
		
	bus_mix(Sbus, aL*kenv, aR*kenv)
endin


#end