Weighted averages for spectral descriptors

Based on some of the comments that @b.hackbarth made in the thread about AudioGuide, I decided to whip something up to compare spectral centroid using vanilla averaging (ala fluid.bufstats~) vs applying a weighted average based on the linear amplitude for each entry.

For the sake of simplicity I’ve done all the stats-ing in Max-land, rather than peek~-ing the values back into a buffer~ for fluid.bufstats~ to do its thing.


----------begin_max5_patcher----------
4003.3oc0c09iihil+yU+WAJ59zopy52sY+Tuys2MqzMyrq1YNM5TqUkHIjz
zMAh.RWcOq19u88w1.AHDfj3TolpjRQgw3mW94m2rcU+y27vrEoeILel2ez6
8dO7v+7MO7f4V5a7P4u+vrsAeYYbPt4wlsLc61vjhYOZaqH7KEl6mmDjEVc2
cAEK+PTxlmxBWVXe6TDcN5QOhOYNA4i4XJGIQBeI+QOpuoIzbj2+n7MDsx7V
SW7w2hwxp2ax9sQIwgEFRAe3lo6KptKRey+0adi9iGuRd5SQK+z.rDgaYIl+
bezguURklOGlkD2IVZQPxFuhTukAwK2GGTTqxhiRBWltOw7XjJlNKLGdKAEQ
oIO0+SbrXQhIyAkJHUnhFeKYO5gQHsXgIZHVVmlTrNXYXS9uknhOqwSlG8al
mTKYGRBpe1jfslmc1eIL9ygEQKClcyku+ZXzlOTDtxK3ygYAaFbFAVpEFbIs
kfhH.4jzBeNK4D62SxoeJMaaP7DjR9TwIkR7KPJQeMJkRBeFntiDR67Vre85
vr7AjObrOXPUgHTj8KsjgP3Fgl4SB4TFgv8ZDB0Oa0jDByJYlRtAjPQwgftL
GLTzPv8vrfc6Zb6GZzEsH3iolWj5w5aEkXuEt9VYgeNpp+756FjABhBPJrOy
pU9hnB+qeMoqByR1GYdS1aBJiRRxH10Zy7ck.Ei1op4FhVC7BiX5ePs3PJGe
PZBp0MwoK+T3pFRnGlktKLIJoosyVMuJbcv93hmZB.ASl81dETt2FqQj+orn
f3ZFXSVzpzDMQzRSnuc0v8dXtig23MYFySjDrqmNC3EPrbhFyAlbe9hfLshZ
QbXC+C.XNMMtcS08KNbcQYy6hRR5HEKR2c5FyzVYOcyKRgF2Nz61zR9S6Srs
9DfIJdJGLG094BhiKma190+kfjnsf2yhnskFPpaLLI.XzOjuLKMNtE+Za4y8
zxJ.iuL74nUEevLPMACviGsqBDMqVKuJZSXdQ66UDrIu8cxK9pUn23V6WTNG
9ohvs6Lw.z5AfYGQ4E4eH847xGrBn0T.bHpwlyoaZnq08GxfWmHTLl79l2ae
6aSSxAqOdeLMYS7WmGDstYG5yVnI5BrBO2uwWJk1WASz0VnEXarvU70ckyKl
sNNM.bWYiTZVqmsgsSRSJoOWF8XAkT0fw4PoMoap7KeGHZxBhy+PvtvoI6rg
hioNUZwP+tPbEmteURXd9zjTnxe36RIEU4HI0Aq55v1Kmq58OdSSWgyz16V8
j019SAEEYQK1WXe3l91OKaPfCwEAwcLbzmIp2bfhOynk.O24MBZ7PJnEAYEf
FAx8hHYTovCqCjt5ZNZfvnJUm8ldJAgOJNpizuy5MDKjp2PrH8FhE14xBzbv
XHCYX9FWNfbPVlRqI0DrjewLt+MlwC+sUAK+1nbB0WXRF0vHL9ohDFcFTqKC
vON3qM7zMN2vXZtQoFWsjGsIQGTXGCNMYaI5LJBAwgfShDbQS3bkzenLaPFl
kCfvtY9I8uXbo7FiKOgl92h8x2ucHtUX4VhZtjb3aAkA3V5DX2GOIKyOCVl3
NV9ygeYWl2+wZr2+I7IYbdmo.NrYkzPJ.xiuTcsBceT0G36+flu8dW9xf3fL
cNod3IHEn74L9guoJh1RL4BkBB+Wo.dIVpYWJXLSgO7sjKtR.uPcev6Edwdw
CwvHo0FNYNtIGSMUKle47q7FaF+hK4uAyJ3V+vCUObA+0YE9YFN.BOvFa3fr
.6FyBCFo25LHRaH9FpO9QOiC+qpB9loeBlMUP5kZ4gbmh8kR84yETIgwFP2p
fnAOQ3EJwExxb58wX61vfjgpgtcEY5M1B5DbuVm6ZjF5zCeyt0lfNAe+1Acn
p7KKxoFMzQEOEKtmhaIh6EvV.yLwHFBw.iqX7bt.yITHFIhXNUhnBL3OU.ZY
eIF66wDvyHov7AkGSRvy8wLNGCtWUx49RARBuGoDRMj6iU.T.h0hYdF30Swy
YDDC6gUPVG50UPIzkQCMm.isToqUDDvhufhofLVABTgvjfISA2mAzGCtFASu
X9TAWqGjygAUmLNQ.iJCykRLjrIGnLf7DJPsPkvvBzuumf.4tACBV3IY5z3n
DIl6I7gHF.5kdHEy110niZ5iOTc.JKTHhLmzbxBGhBy2tR.50s6LMLPtSocr
+2h.AxPyQrl2KKikZBE5v5c4vOO4rjyIvSpSC7bSV59cCwzVWaDl53Etmiuh
POoj6Snm6BC+zIq36.lF6Ekiojo5RnWYP+ABQu0P8g8EHopaiufasG+E6KJR
Gx4tPZLXA1kOZ6VPJg4iNct25Fzn1L5nKKBydxtBVcVj3w72+RZNqTXbCLmg
42GyYqVTjFLNvtWaYzKtLYmSxL3WTa2kYQS.CX7lkIAwtRa2X5c11cmkeZHk
culsQ7qwrMlbiMaOg7WUcxc8TYlVN8Fit37ztOQisNdezp4K1utka5u48t7z
8YKCarj2uacXfdqsjejScno0EvyT.Blb8hcw7Hbg26.h1HDygYADTuQFSGnT
ML5w6hHsyRIgp7YfaRLFRWPuwFolIYL+oXTsNww9iTfdFVYn2.0P0LtQ0.UO
n26dNJYU5y58QiU1+tOjty7aNPITBt6UpyYNSpiuPot4k0b4jqTBFVQe+1pB
qHsj1phnv6.8uJLG.w06Op2eHsgFOz1nU6RAexkCoPYJZid0ZaUCUkD71yHm
nsChrrU1stV+EfapLhgFwivH5bAzLx0ORjwDYBGLR53aFejntZjFS5gcxHME
.mgbPGCQvW0PKHSXnoz9G5qCcxuai7zXZ7sPdyuairdUzGGjgQ24wF6ZksYK
dL5fWQgW4PodoFJwTXJkKFI5TlrnqaXCUWGugJHhAckKTniy8CiJ2CeC0H1G
2ShDXJx3H83FcMFZRx.0IfujqDSMESFl8KhdvupwRMoooUDz0gekSXnp.4W2
Hol5HcshOLcJijzURuwBMohwupQhME8jd4DuZo2jli0gbbj6IcofG2qrShSV
LkQh4hQZJfQrK3I7TjdtIN4o.QvGK8rYD14H9nGjNGsmNGqmiOROm937z8n7
X16x1i0PmrPObZX1uJJ8mMmIkm9wvj81zcqN4LsEEK1rNJNdYZb5QmnopDqm
Yas9zCU8ru2CMm3yvXveJZNESk5Zl.WAWv4MLiT1GbUmXblOhneTHCeIiatR
Qnbp9JTmtQNLVHrucDP9Jc4N0WA2BCiUytEjro7L3HabPR1kktKMq9vHMm5W
+76KR2jErJJzVgBTqcl8ikHoLn0tmljYaAAZTUeZh7pUF+v9pyIW+JffkKgW
bKgJk.BHC2w3.mZtRZuWC9rshfI06X6GMhIpx2dEGiDc5TXb31timTIDRSOT
HrRYuBFZBoceygNuTK.a2aBLHFhDKjDqJTgPXV6NqK9joeOEknmsDVqVo9Dr
vRuU3BhTwnsUqSBoVqEOAXch.n1vUUMHUIQbkxd0QDXW3pnR2IzeIsWYeS2D
zZOmTSvv0ecWXh2OGjj68ygaiVjFuZVCIZKwiOhgkFbGfeXRoEFP7sPCtnxx
2UNg3GCJJFZBQyS826aDKRySKndaJLG4HB5u8mJdxzMzYNOcZZ31XPet1joU
fxjHCZTCFocmbGGBtDNzSSMmgtC5EtcLAvnjNw4Xl9V8AtyoEtgPk7634aSt
a21Ib1ih5omiYY+9tB6LD8u9K+OmITlijBi9AI3TrAJiwDLYHWNXsGeqsAM9
0X3VV46eDWN5MlEx532mHXFPhdKXYxM+z3SUilpisqMlSGGhwIDP9bg0MpFN
XHO+6O5dZN2u6w9zO39u70UYoaBS9EiH5DXbrfBl1Lp.IS36WdEx2kPbyZbE
s7Lg4rRKs8c0oCsZhc5Zs95OJ39junKLJ9Clbo9RqASpeo6I8s3T2.JawDp5
38N9pKBJOHh86CSB+bvIwpiw3tDq9cM1HS8iXO1eupVDiJux4j0et9OcBuhH
puOHJ4aSjp.LPs+miux8jV9yQvjyyxxCtbB6gOtIzD4UEQ8+lGGoqh1Yfs5P
MCE.wDMJ2eNqSs2crVbr8WWJu9gvUm27v97DzmrRbSIaHetrnurrHK9JndmR
P5cp4fFOtF.UGHwKpomeJcUX9jsJNQGsWkznmHXbJCeVlPt0SP+o8aWLLwzm
0licZdCHs+VzxhwkUWjl1ojo9DoT7pKZiedY5tvoGtwgpV6S0e0a.42Og7uD
rX5rxDmm2GxYT6KNkofjqVLZ.z8jx2I8T9BFIzujtQmJiyBmc.kBUB4dis8f
QwlbxXkKqhKYo+usirvRufh2eM3ygqSy19MmKgO+nGQy4Nh4VEj8o2ln+y71
aMUC3Lw8SsPy0Us3Lqi5IJQAq1TfrdwbpWVGkY7cPM3vi.2cdQKbd82b4RL9
wx+XSgPk6rYW7pFLWxtqNwfk0DMP7h7QfSGVhkitvcU+ZZz9qafzIVLhEwgf
KS6B.9cooeZliLN8wcQIe5bWtLfKQpZ2wT8F6mMPcWmvy2a1tSXXNB9dXsLL
ONs4Ui6PXBC4QlYmPeN0ThGa8oCpC7zooWP6uNdkL5V32w7x4joIexlS1up2
ZO26fkh0gRLdHz8Nkp1CNu1tXklenZif7Yk6DEeepRVdkT4zrd1F7EQ8e9hm
rwHU67VjkXwqa8bZw+cTjtKvPMCaN1RSOKOBkS7a6WSC+wtVOz5HN1OgcIR0
qNLQU8Fz33qFvVkTo2UZO16Uuft3ul8oV6YGSSKZO9amWQ2Zrm9bdcMrmhwu
Kde3awm6VoCKKWK5C1v7aZ4xkDXV5yImMENpsUGRg+WeM37IPDwma2fFRIkR
rycHXLl5dB76yBCu.JzH8pKEGVnct6dh6GAKaIEAmM4oXHgvVjPABHNinT3i
84tmF+6gqNa5SVG4FtN+GToGCWSe++gwwoOe9hPB2tojj5yypg.4.pjO1lYi
q+Sn4sfAH+djALKew2mFeAPj5RHwgHl31M2iy21Z61msK9xBdPVua5XXtPYq
Es1L.ejHTYHafQDNR3alDPTbAQ4R9JKbYXzmGdk65CyTmXxAdB0b+k5Fhylh
hFVLYO9BFXPyuzQfrbmBCnYe5fR6WFTTdXxp7WadPNHjc+bud2lwHIFIsKQE
Sf7K2K2RrSwNEA6Famb2nXT+PPQp2OnyBclyF+7hv06iiKNuEXQenUjFQpnN
VccoO5t6S6twFUbN1VRaAURsmYAAx9uhIGJTsL0MhmbX98DkTYCrgVO0gR7o
9N05Yg9+vBulNu.OqqlyWO2sA.L9ZEjIGRZodAlbWtJMSptCS77FzlwohQqn
H12GYCKEvxrx0ZWfPTb68Lcm4y+4nrhu58euI8hlNaO5bm3eEUu4e8l+Mrdf
hX.
-----------end_max5_patcher-----------

I’m just using a kick and snare sound from jongly.aif also for the sake of simplicity.

The results are pretty striking, particularly for the kick example. Without the weighted average, I get a spectral centroid of 3395.637244 Hz and with it I get 2781.255879 Hz.

I wonder if it would be more accurate to also do the averaging in the log domain for centroid.

Doing this for each channel of the output of fluid.bufspectralshape~ starts to get a bit messy as well, but I wanted to whip up a quick proof of concept for the idea.

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

Interface-wise, with the currently implementation it can get a little tricky as I have no idea where this would fit into the workflow.

I suppose it would be interesting to generalize it out, so you can weigh whatever statistics by a specific descriptor (perhaps a @weighting attribute or something). Could also be useful for weighting things by pitch confidence, as @tremblap alluded to, or something funkier like that.

I guess since fluid.bufloudness~ and fluid.bufspectralshape~ are completely independent processes, there’s no way to have this weighting be default (unless ...spectralshape~ did its own internal loudness calculation, which would be a bit wasteful).

It sounds like you need some ways for using basic operators on buffers to make it simpler, otherwise your patch seems simple enough to me. Assuming the amount of frames in your data are the same something like bufop could be cool for doing this kind of thing.

Yeah that would be handy, though it does require more than a couple of operations to get the end result, both on the data in a single buffer, and then from buffer to buffer.

@weefuzzy did mention some stuff a while back on having general purpose buffer manipulation stuff for adding/multiplying buffer contents (though this was in the context of fades and such), so I guess this could be a more complex implementation of the same kind of idea.

I live in hope that @danieleghisi’s fantastic ears externals will emerge into the world, and solve all these problems for us! Failing that, we’ll do some thinking.

Guys, I would be certainly glad to share ears as it is now with all the FluCoMa group, if it can be of any help. Giving you a “dev-release” should not require too much effort. It’s not ready for an official release yet. (There are still several things I wanted to do, but I hadn’t time/energy to.) Let me know if someone is interested.

1 Like

Thanks! I’d love an updated copy – you shared one after the plenary in 2017, but now I’m on a different machine, and I’m sure you’ve done groovy things in the interventing two years :grin:

And if there’s anything you think the community could contribute to helping it get nearer release readiness…

1 Like

That would definitely be useful in terms of general buffery/wuffery stuff, but it would be great to have some kind of native way to weigh spectral stats via loudness as there are often “secret sauce” things that can make a difference for matching (like you pointed out in the other thread with regards to @tutschku experiments with MFCCs and Orchidea)

(I was trying to brainstorm a @weightings feature request thread in the shower, but it would be quite brittle as an attribute since it wouldn’t work without the same amount of frames across both analyses, and making sure to point them to the descriptor you want to use for weighting (generally loudness I suppose), and then what you want to apply it to. I guess the convention could be that it’s up to you to make sure you’ve pre-fluid.bufcompose~'d anything you want to do this to, if you don’t want to apply it across the board, but it isn’t so clean cut since loudness and spectralshape are completely independent processes.)

Welcome to our world :laughing: One possibility would be a second @weighting buffer attribute on bufstats, and that buffer would need to be the same size. It would still require some study to work out what sensible weighted centiles, etc. look like (or are useful for). The upside of that approach is that the default behaviour remains unchanged (i.e. no weighting buffer set -> unweighted measures), and there is probably enough scope to have fun with it (e.g. weighting by confidence, or some invented measure).

2 Likes

Yeah that could work well. Probably a cleaner interface to have a separate buffer~ for each thing, though it would add more steps/objects/frictions to implementing the approach. That leans more closer to something like @weighting bufferName @weightingchan 0 @weightingdestchan 1 @weightingnumchan 7, which is a bit chunkier, but it could all happen “in place”. For most purposes all those secondary attributes wouldn’t be necessary as you could simply apply the contents of a loudness buffer to all the spectralshape moments and call it a day.

Ok, here’s a better example.

Analyzes entire files with percussion strikes, so most of the energy/loudness is at the start of the file.

I also added a bit at the end to listen to the results (sending noise through an svf~).

The results for the weighted version definitely sound more like the sample you feed it, though counterintuitively, this meant that the weighted centroid was generally considerably lower than the vanilla mean. (I would have guessed that the silence would have pulled the centroid down)


----------begin_max5_patcher----------
3775.3oc2cs1iaabE8yq+UPHzOErq579Q+TRZZc.pcZPsKLJBJLnjlcMsoHE
HoV60Aw+167fh5EE4PoQq1sNHan4xQybOy4dt24NCU98Wb0nI4eQUNJ5uD8a
QWc0u+hqtxdKyMtp9ue0n4weYZZbo8wFMMe9bUV0nqc+tJ0Wpr2mNNJMorRk
EUkGMU+DE4IyJW8XoIYpo4KyrOKp9lKJTk5GLtJIO68s+DwUS+PR1cuuPMsx
MJEbvX50QTJcrPvfHNjh3R.AytNBB4iAWGQXiAQ+25OhayyptMdpxzZX88Rl
YGx4S93ML7nMdvxjuZePDP+43tc1x4IYoppxM+.LOaV7b6yN5mUo2qpRlFOZ
cSxWVspM.yM+iW7ByOt9oDHSNLHi3DCPFLPF8bBjIaBx2ljpBOIVhLPHVfGS
3bJPhf.AgJPjqiDxAitvmSnKZbTbVb5CesAVaAevBK+CyGi2i9AvleEZH.D3
4D.AGGUnVjpMmsHeGEOS6+ZvJJZedFDSGJNRkOEwwIKqpxy5fLAgPm219jIj
klY9YCF3FMUOrP4Z8nIwY2Mp4WuIbHV2oEZCrRU7dUV7jTaK6DS11pgAj8.z
hW4wyrC5Sg4.EVUdtN..C27OHiCncBeXDG1SQhybUYY7cp8fvxp3hptDmfLS
FHL.aLDuCgBaE1QntHTsSl.iZCKPAivjo9rte1yX0BMO7snr7jRkGlLQLFwf
aaxbP+lbYxcZM+QW2k2Dbj+dLnvA.k2e62hD.seiNuROf.IXeYDtXHPPGW0J
vfZEXvsBLjvALe22zHBoKDQGcQiHbMmmB2gTP7mTzpMSNydCpuNKd527v3zI
By10ImXibZ9Yqic5.F6Ol5VRnMyIitEhdBRUB1SYopUVoVpByoASdhKeZKOs
xrk1UGeVEj3hmnBRRpkRaDjXFF9IJBwQWZQnUFjVDxPk6V2gCOy5NGXZwjto
QRJB1eN3b9VoSh4D+bPac9gvFcdyw9.FrUApqoM2ptZyVIjShQJvWFKVaZ4E
y5W60Y3PDbeKWfNMKGN.Mm.Z4SVd6sphZKOBtNK8Ca8L3XpDBITJmPDHLDYJ
ZArey+VsmTUmAgHhybPndWKMC.NTgYNo0RifWv0Ref49pnIt+oe7PzRcRQXO
BB6Vm9A9usATvgjGR.C9dmpJtppHpLd9hxN.DAzV+RnNF7dLDgGNAFi29usZ
7CQwG+3a7LF57Y77yrs2quOlRNK0Qi8zy0ekr+M2bS4BM.TDmV9g3EcE6SPs
JAPcp26ukIXVPj+AWl0frAZjlubVlNYutbBj3CCD.YH.Br3hCD4Yk5OesAA5
Ok.r1d2KgHMvDBn.clQhCUrg5snnWaG4R7iHN1j7OyqA6P0QGONZZb5zkowU
pn4p3rNo7HasA0d46ucUhAuMKPH84z9U8NUxcenRMKJ9dUwFTkVvIBRXqNAb
afBivF8B4vAJxyIf5WxKlGm5ALwjrCCSzi.lv++z1uTqoJo6umlGcIM0wktz
05wYVDIXrbWyp659.gfKSgeb0isIVX+1lNyw8rMgHLkmEbghChDRcvcHiHE8
K709lGIOZRK+xTH9ulFUtbdz2+0T8SajSzNdbFuK6W3reBtkbB8J2fCtjPvP
1tk.lK38purnH5OcKL56z+D0uwSksTzDL7Xm8EWnMLdsc+mM1cz2WpySJtXd
9LUmU.dEJnWlz9T.9wJbyjOWbAXDn09AjVRR7jbAXhKiGPUTZTZWVLF5hawa
o3XRCXbrFL+BI1SvR4XIVvkcMSyYxCJ1KXG64CAeYH5lk9zUUOvrCJriGxZ8
SLmHo1V+G+xrT+a5TLqtJmZy83n1GxZQWnsVe4WShP3t3zz5pUPOtJata8sO
H.LD8bbP0yuqHe4hgnnyc4thYjVhnQYmfhNFcYTzWnTeZXE8z4GfgsTSXnOq
Fy4+2JFPtL63W2N90U3O7N93mnN90av0Y2wGRuLN9ylTkG2+DdqN43idkajK
y93eLpbqxhCBawE+jT4f3KrJmOalQ8zeqBb.5oHvAQWFAtaSWlLa7jk2tkH+
2zKjKeYwT0Fatw2eqJtZYgp7fgD78zjWu0gPJbLDB.HHmKj.FERL6Stlfswe
flaho9Hpzj8X6QPvWlcKtAfWwu5Ea2kHNTXEzBrBqyNID.I7HAR6Gl0Z14UL
zZKl6uM55Po5w1py9bDpYLMSUVkjYeQF17gzpoQZir0YPu6o5Ojt6IcPpH3Z
3rXlp3vEUM7cMX+tFdRcs4HN1aWaNXgWxtN3.t4.r1KqZ036zlZEdXjlyw3I
2S15f1OKB0NddZSklSEW+cMLD3IzWi7T6IScG5mdJNKzSouc8oZjBlO8jLD8
D1idRDBJBg8X0SXeTv1gGEHJhWrSSICCuyteBM18lJ7tFBfW8MMDBpaGq+.c
END8jO9FLdH5IexzHL1jOZXPZn5o9lmPgPCi6qIAOUSxGILjLD8jzmLgB0rD
tOvKDIBg7IEAXH3C1gaeLOBHPLu95HbHRHf4S9prPv7X9XSrPXSHeDHvnGqD
BrgvBdTYrOJ6AwH8QaBeVVwnW8L9rjtkO5wgPQwGBDLDk6.4SNGvPXSHul1B
gMw39Jdcx8jzWG8SeY8dsXvfDjwqbqgfyxRd8uuCtrhMks9xABgCUjnd6o8S
BxUF03EKtWUTV+z1NYz73Olag.w01+ZRl6uZKM6nB08Iqddp8NwES+PRkZpo
xy1x69ElaqnFYN+VEYKSpwSs4o6xxpGR2szsMGI3eX4rj72TEWsr78uVkszU
iXsUca7xzpsghI2caRZ5z7T2v6pleyUiVUM5Qte6002t4Y+sHvXjj.gBMrLF
CwbyWBM5qzWPoavEqaCbUiHThDfLOJgg3Dp8JABSwlq.6zLz59B.ktd.HE.h
6J8sf59ZylEmcm6UTBwaNI0lurcxWjWrZNU2TYyyurJ+th3YIJWc8sdLtoXG
b6dCnz+VKrawjZLctFPSV0lMYdMSFuZ4pilc6S.wSMeawsEnhQZ.xZcDp1Rs
Wwc2aC6b6IBBmBwVjDIwBo6JJDv1oQpT07c6Otfw31VH.PgvcktqQnsaaotw
SM.31sFo6D6fDx3H2Tn..r6zwFM1rIL1189jLi2hpYZEKQPla7thWf3BBd6o
UuXpMyhGfr5IAZa5pngjJ3.pP3tZuA3tzU1p4Nl4Ob2UtOoyBaskWN.sv0+b
gJK5MwYkQuQMOYRd5rQafnaAOR.Axs7NM+gv4NZ.R5nFT1JkuSzg30wUUc4P
r46LwusQ.sMeCIz22JTDjAzu9CUu21Lv.8S8aFdaNnjZjLc.JgCrrQCYDuqy
cpRGRXcKsa0ut4l2rBWepIibrm9X11t5GvcdAU1.TQOi827tYmWGtenHYyuo
D1yGyY9scELXL5281+9.oxT.mYme.LJFZoxPHBh5JjCzDw2oMX3uVga9pX+8
Dxgvz4L5B7KQLhkjPkP87Um7SwF+plb61lyYxCwFDRO7oLWXTCcvN7jWd1se
A2u349zN49meXVQ9cpr2ZgnCvwgLrVZyNEvILor9JfLjTb6Y8HY5.o4jZk11
t5voV4YiNU0WYuj6C9AcjYwuVxEK4NASrrN7j4VTbXHkaYDhl781+pihJ2Ii
8kpL08wGjq1mgGRt5OtwWiCsyX2OdunAhA0WE7g0OYhW8TaP8x3jru44nx7x
brJ9y9WE9gV4mSzNmCR4AV6vt9GmkwD5I0f5eTllXpCz.3V6LZ5JABOEkaeM
q915cTK1W+Mj30qTyFleXaQBZCqXm0gsd8bEIeYZUQ5IL5C5.x7EUSmhGmBg
ZGJwipzyujOSU5spnmAZOIznkLXBpAOHIjysC5urb9jtGLso1rePyyvP6WSl
V0OVcTyzAcXZ9BOu5IW1FuYZ9Bk+oartp0Rr4OslP9kCjea7D+MEO8yai4zq
9RPMJ8hqlzaBzsrjuCFo7QLSn2le2cq9+WDgHc1NlTvb8ZugtVPvP6ZxH0aq
RHMo+87d1XoGQ38cw2qtMuX92BNBO7rGAioAx3lEW7oaxLeCNcisZ.Cj26ag
lapZw.qi5AJQAoQJf2rYNMaqiv1+AnFbvdn6AunEAu9agbKF+ncpPU..0uNP
g3ipy0Rt6tSzYYMAcjuHsG5z5sXYuKBW0u7ar+zlHcfMiXRpRGxzsAf+Xd9m
FEHwoOtHI6SCc6xzVIPzDNFy.ZUkNp6pGOeqq10itYO5658xv933Mup+.Bdz
k6Iy5QaNjKw0a8y.TGX+GSOh5uAdmL1svu8EkKHtIexslr2YNZOW5jkRMoRz
eJzs5R0DAm1nKtZluqZi.jj5Shhz7cyS8UbQPW0y73uvLuMvCSLRr85V30bw
Sa+b1x92YhLbIFZLX665q+qxCgoH41w0LzeXnmG15qmo1GXGCpdxoIJZNfF6
eUGZUbg4ToccqW8HFh+TNmZa6c32rn6cFeXEcaiyzWvqqg6s4+GSWptANziR
GjWuWzq0vjapbExAXQ9myF7HrWs0.NB+qODO7AH.IotCnAmiwHmuCBpyXJ7C
vWVnTGwHzhdMkhCxLA2C+f60Zksrp3AO7DD.i4JRHCnGbVnjIgRZ3Gi+K0rA
O93MYtAaV+CnNhQnGe+GUZZ9mGNDhntCkDW.E1zMATMqj12gYiJA.w4v.POG
M.61W7x7zifhzTBIpNiIp6v8D7is1hkEKROtjG3MmlNBjp8+shTFY.ZOYnR.
tDiPT.SZcBPBJCIBocUnlpRtu6ctqMNSyBSVaSfMOeogYv4VhhgV3cDeFQKn
IqCDvqOovZ1rD2IZ+3vhJUYyJepEAYMHGdeuVOlw.NDvcaQEgAj0mkaNLnbm
p3E8cRt2nXTuJtJO5UlUgNJX8eYk51kooUCaCVLuzJbKjxZxU2T5icO8o6dv
FETJzURaFlicuyBLf6+2KGPP0YTmIaJfquGI3BWhM3FWGLRhkAU8rRU9z58E
3ylp47vPOF.592LAYWCItddQ6bWuKMdU2AOeeC11vwrdqnHTJAtzR0bYR8ds
y..Lb6yL8N9y+TRQ0CQ+s6xOJ2Y2qNmcG7LelkKpmBseyt8h+3E+O9vuFhA
-----------end_max5_patcher-----------

And here are a few example audio files to test with it, but feeding it any ‘single attack’ sample should work just the same.

attacks.zip (650.2 KB)

attacks2.zip (527.3 KB)

And if there’s anything you think the community could contribute to helping it get nearer release readiness…

Well, that would be wonderful :slight_smile:

I’ll try to see whether I can tidy up things slightly and put them on github.

If you want to help that would be amazing, there’s one thing which I would love to have but which I am unable to do: a general off-line processer of buffers via “lambda” paths. I have been doing HOA lately and it’s painful to wait for a playback and record, whereas I could just take a buffer, pass it through ICST/SPAT/HOA tools and have it bounced. Think of a [ears.process~] that takes a buffer and uses a sort of bach-like lambda inlet/outelt behavior for signals. You would be able to process offline any treatment (say, your own beloved timestretcher, and not the ones from rubberband and paulstretch provided). That would be a game changer in the library, I think.

After discussing with Andrea it looked like this was not possible and seemed more likely that the behavior should have been poly~-like instead (which I hate, but the best is enemy of the good).

1 Like

What was the obstacle? If these are signal processing objects you’d be wanting to use, but as if they were offline processors I guess you can’t just make an instance in C and set to work because one doesn’t know its processing mehtod, as this gets registered via the dsp64(). But, maybe (mwahaha) one could send a fake t_object *dsp64 pointer to that function such that the external ‘resgisters’ its processing method with ears.process~ instead.

@a.harker you have much more experience of making the Max API go to strange places. Is that a totally ludicrous idea?

1 Like

Well, the obstacle was exactly that: my complete ignorance of this kind of hackiness stuff. :slight_smile:

Again, if you or @a.harker would like to contribute I would be thrilled. I’ll put it on github ASAP, and send you the link. Differently from bach, the library should be rather transparent (well, still C and not C++, but still better than bach, I hope).

I also read @rodrigo.constanzo’s post, if you think you may benefit from it I could weigh in in one of your meeting and present the library at some point. It’s really a stupid do-nothing library (no intelligence, no real research, just development), but it helps me all the time.

1 Like

I would be down for that, particularly since it may solve a couple different problems and/or patch holes in the current FluCoMa workflow.

I would also be interested. I’m using the 2017 version and would love to see where it stands now.

Is the question “can I load a max patch into another max object and run it’s DSP processing from/to buffers”?

If so then the answer is, I think, yes, with a few possible gotchas if certain things are in the patch, but it’s little involved and you’d probably need custom “in~” and “out~” objects to feed the buffer I/O to /from the patch. I can’t commit at the moment to contributing a full solution, but I can definitely commit to appropriate teleconferencing calls that might be able to outline what that solution would look like and some technical details of how to do it - any good?

I’m not entirely following the argument above, so it may be that you are already aware that this approach (which would be poly~-like) is possible. I imagine you might be able to make it more lambda-like, although I suspect you’d still have to host the lambda in a custom object - I don’t think something like a sub patcher lambda is viable, either because it’s not possible, or because it is, but might be too unreliable - I’m not 100% on that and could brainstorm - I think if you want it to be able to hook up to anything it’s a no - if you’re comfortable with limiting it to subpatchers/abstractions, you might be able to detect the patch, copy it internally and run it that way, which would be relatively safe. I’d need to check the API for the copying stage.

1 Like

Hi Alex, precisely. Yes, I suspected that one could do something poly~ like (I think you already did it for your tools ;-).
Programming with polys is less immediate though (1 more file, handling ins, outs, etc.), though, so I was hoping for something more direct in lambda style, say
[ears.process~] X [supervp.play~]
but I would be amazed even for something like
[ears.process~] X [p supervpplay_inside]

As far as programming is concerned, this is not my cup of tea, though, and it would take me too much time to get into it right now, so that’s not going to happen soon on my side. Again, if anyone else wanted to contribute, I may share the github repo once I’ve made it. I joked about “commissioning” the tool to Andrea at some point :wink: but it doesn’t looks likely in the short period.

In any case I’d be glad to share and discuss the library with you at some point after the plenary. Maybe there are other ways.

1 Like

If you want to chat sometime that’d be cool - most likely it’s easiest to understand what you would want with some discussion, but the bottom line is that if you’re in a generic patch you can’t control the DSP (max will do it’s own thing) so anything you’d do here relies on you being able to internally host a copy of a patch of some kind. There might be some ways to make it look like you are just programming in a lama, but then there will be edge cases where the artifice becomes apparent or has weird edge effects - again probably best illustrated with examples discussed on screen, with some mock-ups.

Ooops. I’d forgotten this thread. I had in mind something much more lofi than dynamically loading patchers, which was simply talking to compiled signal processing externals in such a way as to get the address of their perform funciton, and passing a buffer’s data through this. Something like (e.g.) [ears.process biquad~ @inputs 0.9 0.2 0.3 0.9 -0.99]

I’m sure there’s a very good reason people haven’t already done this though :grimacing:

Well - that should be possible but hacky - it sounds like the sort of thing only someone unwise like me would do - I’d advise copying the object internally, making a suitable call to the dsp routine and then several to the perform routine - these are fairly easily retrievable. You’d run into issues if you are reliant on the state of the actual object in the patch (and I wouldn’t advise sending these calls to that because Max will have it’s own ideas about that and definitely that conflict will become a problem), so for instance if you send a message that changes the internal state of the object you won’t see that when you make a copy and then it might get too weird to be useful.