Fluid.concataudiofiles but non-blocking?

Hi everyone!

I’m trying to concatenate large amounts of samples, but currently the fluid.concataudiofiles gives no clear indication of how long this can take and if I should abort or wait a little longer. So I’ve tried to work on a version that uses @blocking 0. It seems to work quite okay and prints the total progress.

But now I noticed that the progress seems to slow down quite a lot over time and was wondering what could be the reason for this or if anyone has some suggestions to improve this patch? For example if I concatenate 1500 samples (all are between 1-10 seconds long, total length about 10 minutes), it starts out quite fast (like 30-50 ms per file), but this gradually increases to 800-900 ms per file in the end. I thought this might have something to do with fluid.bufcompose~ automatically resizing the buffer if the length is exceeded, so I tried to set a total amount of time for the buffer~ (since i don’t really care if there is a lot of silence in the end), but that doesn’t seem to make a difference. Do you have any other suggestions or should I just wait patiently? :slight_smile: (now with a clear indication of where it is in the process I don’t really mind, haha)

Patcher below:

----------begin_max5_patcher----------
2000.3oc2b01iiZCD9yI+JPn9gVozqXy68Sa6ei1pHdwIKWI.Ba1cu6zc+1q
sGf.YCAmbAuaOsRrJ1lvLOdlmY7Xb9x5UlwkuPnlF+tweYrZ0WVuZkrIQCqZ
+7JyCQujjGQkCyLo7vARAybCzGi7BS1dZYAoqwhlCYE4Dl7NPGarrg00pUaq
UQrjGyJ1usljv.4.Yi9f0FCaGO4+bEWwVevx3eZumrT4SrL9i+pK1Tz1WWuV
bYy2oNTUmUv96hp5x80D9Xa6OOqfjT1THGD99niNfZAZmq7ps840QaK26oRF
EWVytOyTXrsTKbBjxu2klorsbtEsHtgwJKtn3VEUGcfvH0aIEQw4jgB8XUo6
NflXeph.5gYbTwdydo9BZpuEnvcWOulh+erlhr.iwVCzYzTqaQSKHOyu6W68
YD0jlUtKKm6sUjDcdiT6EReQx+EFJ0W740WbXf4vuIRcqV1plqLEB+SjZZFe
l7nXsxLppZPyqFbKBr4ikxunfM8MkU.Mg6apl7TV28er0nZt9v3JSSsTiMew
yw73WSYJotnISJJPi7YoVQRNeTvsmnUQIvMKl155d.B4IAkPr3pO.W9X+iPD
e9dedYx+RRGXPxmKpHEYbxTBkSCEwZk89tSI6hZxYa2UVvnYeVJAHwy3L8uq
UBOamBcPJ9+QcVTduBruNiGSRHDilIDM28335lTaDWOpLxQTDUclalaDvgkI
5jxUxFZbTsXhp06ralxjUVlOtq96Kmri01cUVQwInHqrZ5Nqy1+3Et23RdmG
tz2srG51lBn2sbaB1VZzSiQaVTddqS63u9WhJxNDwHrLXJ.a02IvP8HMotLO
ej9B87zY5IkaimPdNKk8n7AMzXfO7rpNiHy9Y4zr8DJabarn8zwsPYeB.8AM
0D25CukQNTky0hwCf6cjQYzGKel1NvNCsg.vwjmF5SOjAbT6mvDxc9nQ6I8d
rCoCetl6XOrmQzf3wc7ZpvySG1SENEcnSX.3QXAQANkN7TJQHn9ptf.sTLK.
b747jbRTs1ADLmSxsGPbrmCPBum.hT8lTkstMUdTHwYTaHK.aqtqSo09CExt
LOEc9yhm1uXLLoS3dKRIRDv9NBWfpNIdglDurlwo.PAeG0.CzLfwfkJMFKP2
QrXTRVick9MNy581OZWdIOgs4rpP9xjHbCfjKCElXWxYBG5ZpGLgYDaftAKG
7rdZaDtwp.MHAZ3h.yK7b7L3PjlflnjjlCSBM12l8hZPBXs3.TuNyCIXMAI6
idCBMGJgAOHkUULPrzDZ74bt3364ajSJtAT4htPB2m4CVAEPo0Pwe1Xz3.Kc
k1hLokMFznCUTCKsayXCFMsYuD3MKx3a+idBc1t1PXGW0RnC6qKVEJI+lLQT
JFz7rsV1CJDx7Y9i8B9QlsE4HMSrUlt0yV2zsIOxmaIuILtHWOoSDTOzP+4Q
GrtQmZx92RnAEBEJycVnwIP2PCMOKgbgzc0gkCP+FhlGdB0UDoSWWld3YZoc
aWboBlK5hmQtaXFOHWYWEWfkke1.a7PJIWTO2CjaZESVJkkaqei077tN5ZcP
6IbslUC4xcCJt8r9NJkqKxQVXFKo8Rv79O15ZIzwM61Qp+lAr4M+Yyt68xog
ZLrQwJX0k5KvC25lcQjBqMlFJg8VrX.HyWGHnsBTM3.sU8kLi36s4hnDCaTt
bmfWUaZuyWXJjyO5UeoaAR9pV8Ej1V5XJgxnrnZ1Nw9ga7SnMFvxbz8dC.Pj
GDkBMuGEJPWAu2k2jk9ANkbR4gpRJ4aFOPKap4o8wIQS4jyhv3TVVgbiYOxY
a7PrXqb454EHntwXbcKEsmGWY.FdifblOa.jefli10Bmusw55VrJjDID36h9
pZiWOm+W7RkrjZXS65wfWbALZ1Zfgb0FQVMoJOJQvf8lUeCfX2aVpq6aZ1Kx
FapRTMv2P0s0DG5M4d4kmQY+hA+Q7H0fUd7cWhd1s1C+dG7THe5qYCgwgWXK
gKKy4Hmb4km7tVN+9gd78zQ7ZYNwaegT7E8edzDhD1p3vawvFiwpxffiCFmX
IBxQpzr40JEgpJENA7QhVHovWQoXIQBNYihPwBJDRSXkjBQDikTN7TEMBsVT
4v8pjCzhIGXkkC2EEOT1JMDu3xARY4X4lWrTl.Csj3Qf0UYerX3gu86hvJhM
vTQ4v60irrNEdMmQu0BGNXZgyZYDNu.ksnse+JbHsOo5opk+xRD3gUkXzKP+
Xj5dk1KIK0U.R52F2I7ZotVP4.cM4lOXjGxRqJ4K1ocwJXa4qXM10ex+gBZK
2Jt+SKlloNE2hFjxw98Qxk1JmjKxYIwCaWUs3VRo.Gbso3pQFT0ENj9YtPNW
kvsX1yR4.cMfzBIGp6eq+7UTV3DafitsjTc9ydIWr64T7IfH+fkTN7CtppjY
c4Hwxc80ySFlMv9Ue.E.Af87f3v3EKNLTBIklmCVxh7.xAVE4vW6tBWivo8v
Q8EATcKyyVd60COltlhyhY5V3bmtU75GkE2vfxdO7bGeUmOx84kwQ4mbnFO2
wmb8Qg6JOh2rx86yIK8gYe3F9boekET4T6iCG86SfbHi2hAPuO0rnU6ek4f3
WAfAlCSFrK.rnOKFq5yB9Vl6YINs98lceGOKGk0KznmE.ombR3EOlSNA7mb5
2e8Iee5S89om3coazTmz80ec8+43DTSJ
-----------end_max5_patcher-----------
</code></pre>

Without looking my gut says that each time a file is concatenated the destination is copied to and is longer. Each time a non-blocking process is triggered it copies the contents of the buffer into memory somewhere else, so this repetitive copying, combined with it taking up more and more space likely contributes.

Let me ponder a solution…

1 Like

Without looking either, but reading your about your buffer length, I have a quick test to propose to do, as we know our non-blocking is doing suboptimal memory management at the moment (@weefuzzy is on the case but it is a deep design thinking one).

You could try to bufcompose the section you are analysing to a temp, small buffer, and pass that one to the non-blocking job. If that is more stable, that confirms this is the case. If that is not more stable, it might be something worse and I can check for memory leak and such pleasurable things…

p

1 Like

I’m not entirely sure I get what you mean here. So at the moment I’m not yet analyzing any of the buffer contents. It’s just only the concatenation, and I’ll wait till it’s finished before doing any further processing. So I’m loading a file in a [buffer~], then increment the (deststartframe $1) and then process the [fluid.bufcompose~ @blocking 0], the bufcompose will trigger the next path to be loaded to buffer etc, etc.

Do you maybe mean I should first move the content of the buffer~ to a different [fluid.bufcompose~] (like basically making a copy?).

Ah! So that is why it is going wrong. Non-blocking is not useful there for 2 reasons

  1. multithreading needs you to copy the memory to a thread so there is copy overhead
  2. you are only copying so you would copy to copy

But what is your problem is that everytime you add, you have to allocate more memory. But I had that problem and even made a solution :slight_smile: Check the Example folder in the BufCompose section and you will see something that is doing it in 2 passes and it is very, very quick. One pass to get the dimensions of the final buffer, and one pass to read them all in the right spot. Doing this does not need the buffer to grow every time you copy (it does it in place) and then the speed is linear.

2 Likes

I see, thanks! Will have a go with your example.

This is the good solution I didn’t know :slight_smile:

Alright! This was indeed what I needed. So conclusion: [fluid.bufcompose~] in combination with [deferlow] and presetting the buffersize is blazingly fast. Other big bottlenecks: don’t print the progress, this slows down the process drastically, and the fluid.waveform~ for displaying large files is also quite heavy.

If you use the regular [waveform~] linked to the destination buffer it actually shows a nice ‘work-in-progress’ gradually building the waveform while bufcompose~ is working. So this does the trick for me. Processing the same 1500+ files now took me 2 seconds (which before was definitely around 5 minutes…)

Patch for anyone interested (although very similar to @tremblap 's example). Did include an abort button and input is a list of paths similar to fluid.concataudiofiles:

<pre><code>
----------begin_max5_patcher----------
2591.3oc4bssiihiF95TOEHTewNqxTK1liq1K5Y0p8kX1QQDvIE8RvHvzcMS
qoe1WeBBjBBljxoPZ6VEIwlC+9ye+G7uM96OswdO4Ubss0e25Ws1r46OsYin
HdAaT+di8o3WSxiqEml82h+J9.o5zOr2JqsLll7RVwwcU3Dp7NA87d1YqEDE
x+.E4v+vO5YGqeScQjFZNlR+8Rr7JrOjSho1au5WxypEeZ2ca12b3.tpH9j3
1XmPJRho+6rbVSRcFYohZH6+xOCCgskVzbJqfI.hlj24BkhknTedg+4SOwOr
USrIgb5Dtf19Tn3WE.hc7dRE8Z3kiiDuPB7xW7CmdvUuVAxwczVAXzVgyMzJ
12PojBMDWUura6wo6c2GWbzd7VC77Cph0ORwU6vEw6yEWpi9sTvMzRKveiID
uo6pzJtIMibfwijLpqfE.nDKBEXQTj3GvaBKfQgi1yBGu81WlvUpVopYtwlK
7eEWUmw5IOe1ariKK6U7ldWBGa9BQbiB21UTVgrHXWQU3ul0d8mKMthgLTFr
zTI0Ee0ukmxuMjTlZZSVWGknWRIRh9CtNbcYbh7h4casUeFqQBlVPnDo8j+H
7LVy5tOlSR9u3zdbGVOPItHqnrBWyzMioJQuq5T7g3lb5tCjBZc1eHD..qGb
r5OnDvQqryLzuTkEm2I+GqxRIEbgXPGAu31GGiFIZM7imaLhynHtbjKlQWXn
xDUVyZjM06iq38SJEo1NJaJgjOrptqKGefpptLqn3BTjRJmtxpriubkqcOgU
4oqcuE0TuqoPV6NFkftql4pY34EmmqzYGd6eMtH6TLESyjcALKTsUJMl7RcR
EIOeP6UVyWGolTFEOA+srT5KhGTex.6zyJaIQ1c8xoYGw0zgkQiOVOrjZ5uK
A8dE0rWoBuihOUlyZECOAlxAyuW8KjuUqNwVhVe.3rS79pz8M.Nn7KLDxz8p
iOh6TX6aMLIGGWs0hyUyJpiOUVa8IP+ybLOD99O6s0xKPXbD.QWZVbbSi1Cp
tmowvv9OvwrNNkGgMsdET1btQ.Zfmhg3SSwWHYEVvYfj.PODwCnIfrU82j.i
2j.CXRfA8X.l+lEvgEovL3hqzPtuLlBWO8.FYLgShJtqW5xOaoKjn3JvHNw4
tgDz5ERRJaR39s0DVfxOdeXJvaP+YcAKdNdbBRK579.Kf0KrPsbrly+C.HFC
ERFVEBpGljUHFdI+iIAFma.Xfui.yvgXNxvL+OEyfMHoMVjy4wZhbu.Z50hC
htgVryCiJLSiMzkqaHS.AbAzfIQif0qhwQdni5.GnfEoVLMX3ud8oTiymkb.
BQBKmAQsJA5.GhwuesXx7uEXAtZ3Hx.UUtStaNh+JNti+wb7CG+mgbrPEttl
AhcM6G9v0Kb7G4rt6.+.qb7b9P.9B1gqiLILnELZlIQFm0qVSBoofhqzx3pB
S7AKJli1+tF2waZOwdShPtOFDJEe.WkS9lV1VBj4L0y8Nss34+A6L9ZoMYey
AYxisRIEXqOArpwI0ZNXXYvY.j28hPdqWyMTq85MxFkwFcCeaP90uDPbiVyC
rIeVHQMmKQKJy.bCKWGUB+fGUyUPkxJlMQqOKFuZICHDy8vrC.rUQxWk.xvQ
4N8g.+06vbjyx4OrXPP5+r4fV1X8c6STzLc.ywSPdev7jqYvsBWlGmfmO4zJ
.Rla.+60DK5idPPWCSRw0zZZbE8.etUmGZ.A98HO.m6M5ejy50+yg7lrzmEt
oOURpw+v5y0jlJFCRomY8YN7kUHlxPq2t1BlgeEIh.DghV1vJ6zDmFTAq2b9
mPxysXXxK+RQ5+hOgXZMoHtNiO44yLoHWCjf2h8b2d0vm7wzcxIZcWLkVksu
gJmksMuAe1XiOse3jZJaxsNr5VQIC6CLeHV7+qWLEpjk5BWFecvmS1arhmlp
L8lKSUVhdORB.DspiJmEFZtdTltz.rvLmcUEW35kpPsxlUaB4C6sn2VBcYVk
Hv5MJ83jjlSyNwCBvvUNpVW26Oa7voCu.8QqHIxHhlpQRDQst+t8ns.q7A2N
mUEDPDN.zcwitcZHYEOxVsV1HJLocNJBtWJRv500C90xJqOc.ZIW3HV+U1O.
ZZsUMNevciOq3Dl0lF.8GIhJzE0ZqA.dWSF.vc8pZwWo3GZJJv5ZxQBMdZZA
VrPzmDWVyKojkM7LE5XhwmE9+KCO6Zomguzcs9zrt.bA8Vh4d28Lxthmz9CY
EGH+PO7.AjKGbvhhvV8wae4RtdJWtA1p+6HlIus5sbFTKaPT2wIMTcKY7tWM
sKEI986uvcU7Sho5p+cMqHE+5iLgm034WSPdHgWQULC28brAgezKNYwySOS4
nqwMV1ToAil1Rhyzs6oHPbep+jv2TsEkb9MvodT9D7ACes4HaQv2Uftf2Sna
OgjyfNwDkUVQNVwTPzVK776aRdVwTuEABDgW+3voLu4pVc6502ZH5zKW58NQ
dPj7STqtykJE77rokTzJtFQJ3KQeKfFRAexRLlTzdymWJ.lFKzRJ7MIuvWWd
gmAkBOcwBWShEg.cwBjjFaFo.tDovXXg11KLoUq1a9rRgmIYm7EJidXwaIPj
pT4KjJvHhlu1puvoEMGyXYQWa8PSxiERATGovjdbf5pSC8LMVnEYwjXQntde
4qwSKjIkBcXmAlziC+UnPKrvnRgXzK5IFAlDL7WBwvXgh3ujtjgLnSYokD1H
OTibHTjal.O4ayoXJbF7CjuZoEEHyau3Md2LQ7pcb2f0feTQZDdrdqz1Q5i2
Eut9NFoIXXPiuVY0hV4ZRMVecCUEZRin52MgdzLHunkHZfGJ4V2fADvqoFxk
9.ziOJZnlwu5a73W0QQG.MnT.z2+gIydjtYIvyjlab0NqhlzzKP23WCMZ3q5
JEtlTLP5FAAxniwCpKwvrC3UW65vGtKGftNpAFkzBVR2DvjRA3ilr.zMuDPv
ZfxJL5AdjAA.BWhnYrtIci12j98PxbBMOR3YP0FjlwjALokdsc2LoLnJrc2G
bt0Qz2uk88si4j8w4WrYsM11B2SmEN0NWonsMblXkajkWhTpsyxQlmuAl5mx
nRT3YpxfG8E6Oj7GyE6KjWrmP918Cxo2KHubefTzKH2T7tn41gZmhe0ua2fr
c6VbHFDmjfKnIjboT8qVNOGtke.EAA97uE3DE53xZv81WN2er2UHRZ04CNO6
0cd7kVh3L2kUvQFb6yPbdsG.sowRQr36loLg5x86O6SLoOq0nY+MpzAM3dqH
gwaxCZrtPjGLhKHn.nmq3av.WOv6sXMXg2Ltfs+3gr77NwquJT6Biv9XUbZV
u8vHYqAz024y9Wv1Q+Fn+9io3xfsWVPXHCG1N52d6k0dUvHGPjfifTbD92XE
At3phKNp1IMC5scPVVQJIUcaonOih5N+FJoqg14jryry6DqZn1gd8h8WKYZv
tDxhKiV4.EeigRrV4sxrjFYlXGe8o+7o+GP+x3eO
-----------end_max5_patcher-----------
</code></pre>

For anyone interested, here is some code you can put in a [node.script] to recursively search folders for any audiofile that is a wav or aiff and output them all as a list. Make sure you $ npm i fast-glob. Combine this with the patch below to use an [opendialog] as input.

const max = require('max-api');
const fg = require('fast-glob');

max.addHandler('load', (p) => {
	let glob = '**/*.+(wav|WAV|aif|AIF|aiff|AIFF|mp3|MP3)';
	
	let files = fg.sync(p + glob);
	
	max.post(`found ${files.length} files`);
	max.outlet(files);
});
<pre><code>
----------begin_max5_patcher----------
782.3ocwVErbiBCC8L4qviOSy.FHIrm5+QmcxX.mT2gXyXaZSmN8eeskAJIk
1PaytaNXLJRV5I8jLurH.WHOxzXzuP2gBBdYQP.HxIHn68.7A5wxZpFTCKXO
IKd.G5+KC6nADWJE6jpCMTy8HsU46QERooWMq3x64h8aUrRi2awjnkQgCORR
bOHjkQne2Yjr0TyLlmaXdKv3PDlKr12qAuB7sMdtgj06KQ6AtvZHDtwuIzeb
fThS3qKV3VB+Y3tQwZXhJTsjVMCzlAOVmOCvNIJS9BnL9afxCLsltm8NXpKU
7FCRanpOqnllMBkqR+tnjLIJIWMTVzZLRwkKWqfURZ+5GiiBpX+jXIN+M2nn
GXFlZKSPKpAKi96VM+.NqzwX4zZ4dzNY8Lns4iVubK5GlKHQ+e5QExJ1xNFr
qO8lc7Zld4CZzszViDH0nXzsO4R.n3YzFmC7bxpYlQllYr4qjM5jpoOxp1ZM
2FRaoFiha4x9A3ACIk.7.rFchA3J1NlZDsK.CHdfc4S28IcHlw0bw42O.4Em
7SqDZYqprG08ijQukYpXZCWPMbam2HkR7JMY0d1dJYFdxku+4dh7OySQyI6k
cE7jaD0k8Tz67jmfPaZdjozcZCNw1T9fDHZaBgW4B+q.KFqXOx602KgprMZF
KktUAAF93pTr2TaqqRzx63nV3Yco17b84jRgc1p+FL5wUtoD.ZbTdZas4zL.
srjILkxZeTcGJZ4lP2RRNIdka25n7MQo1F8Qc1E6GYQLLFXXIZY1fdtwNfla
4BWlg06CPu9E3j8IyvtpkxFT.z.bzAfC1nGPezYU2S.LL93yf7IfMkjjQxcA
RxZRVJrirNMK9ZGVm70DSGXE6sCiqGBuwCw5Ghh2qnUbaTf6GaApGOT6VY+s
NbxciJfclQ5Ma8lM17P3j6duY8VQxihyANRRGGwsyJJ9LqrWB5SYj0tBdmzF
krQp56srllGNZj8.P6RrCkgqFq5zti4UE8WCMa1EDKoVZUDA1YyRVT9cYV9g
LvU7tfR2P8ytfuDXwqK9CHjbwKI
-----------end_max5_patcher-----------
</code></pre>
1 Like

This is awesome!

2 Likes