Faster-than-realtime sonogram creation in Jitter?
Although I’ve got quite a lot of mileage with Max, I’m somewhat new to both Jitter and spectral processing. I’ve been studying the J-F Charles spectral/jitter patches closely but this question I’m left pondering:
Is there a way to have Jitter read an audio buffer and draw a sonogram faster-than-realtime?
The only thing that comes to my mind is an upsampling poly but I’m interested in any/all techniques that more jitter-aware folks might have in their back pocket.
Any pointers greatly appreciated!
You can surely achieve this with [jit.fft] but it’s not trivial: in addition to the fft itself, you also want to perform the windowing (hanning or else) and the overlap add…
You’re right, that would be great to have such a converter!
And first off: a personal thanks for your great tutorials!
Attached is a "proof-of-concept" patch regarding using an upsampling poly for faster-than-realtime sonogram creation. But I’m definitely interested in the jit.fft idea. Problem is I seem to be quite lost on how to use jit.fft. Do you have any pointers for me to get started, if I may ask?
Indeed it would be lovely to get this working in an somewhat optimal way.
So you shouldn’t do this in the audio domain at all- use an uzi/jitter solution. I am attaching two patches that actually do buffer convolution in jitter this way.
Unfortunately this is a little complicated and I don’t have time to comment it. Also it doesn’t do windowing and uses zero-padding. On the plus side it shows you how to loop over a buffer using jit.fft and do some processing.
The Offline FFT patch will hopefully be a useful starting point – you need to add windowing though, and maybe lose the zero-padding. The other patch shows one way of applying it…
And thanks Alex for chiming in!
So I’m gonna have to take this somehow reeeeaaaal slow and step-by-step… cause somehow this move to jitter-land and jit.fft got my head all confused. I hope you guys can bare with me.
Could you confirm is this patch (pasted below) essentially doing the fft analysis on the first 4096 sample window of a buffer – still without windowing – and storing that info in the first column of a target matrix?
"Baby steps towards greater understanding" is my motto of the day.
Thanks so much for your help and patience.
----------begin_max5_patcher---------- 938.3oc0YsrbaBCEcs8WgFuN0id.XnaZS22oa5tNYxHCBGkBHFPj5zLoe6EI AINOPl3GLvFqA8.N2it2it55GlOawZwVV4BvmA+BLa1CymMS2kpiYMOOaQJc aXBsTOsEghzTVlbwElwjrsRc+emlmyy1.hnRJ3NVgjGRSRtGDKJ.RZwFlDjR kE7ssqLgmwBEUY5kia5LmJCuo90bcAKTZfEx2aI7B.wmnZPXWUCNXIDbUyh3 QZDHVe6mvn1WerHSlQSY5gtrfSS.eSjD0NbVUJOKgI0FEZm0Tx+qdMHX824o 4JpjsSFp57w4yU+bwQRZWlQStujWtX+lObkpwU+.xuCqGNor9eTIyqjRkWSL unTBbfAdfRZZdBqDHhAqqhiYEGnCChfzMtVcXP9SJJ6m5HomYrPQRUZlhqdQ L1W9nbliq18xwogyfV4L2QImkw9SM5dCkkHnQqoYaZGv7Uj2myLl9B8fOYmu K4noCRfVAx3O0UHH57K.gNg9SNKsH8fMJtdXcSfMydZEEQ5gU6zCqd0jxpw8 vpw8vpcmTVMZ+VMwY+FsyTRx6VtbYDOMklC9p5GD.1o5W8butMwLvB65fMIh YHJsgzIeQ7N6DF9.HrTVYIcC6MLlPmJR8zLIgzIaYke7MAONZ2IeiSkWGGSb PRG3y8wD1oGSJGvihbLQbdAVIGuQI4XIXKmF9a.9DFi4pIHWhUII+yNMgOcz T3cKULUHsPJxEI8jq14odvZDcyJqIn4.mRrlhxpx9PtWebmMjVpxy5UKIjyt dN4zRaFN.DGKq+F.LHt9h.RBt96CAX3yAOGezpSyUB77sd47o3IhGkVum1up IQ5tz5ClZZ80NT63McZ8jvAFxBhrdGSmQomz.d9H1zX+7QDYpozap20+TZVW KYkxykhOFpSunwYqC5yaTJ32kbUAKOgFxNL8JGcwuHlRf4YSthLkTq5s6jVL S46r+RgYpBs9fNe6hTSpS6pJYQkx56LCPGnKjoFgNnU6+9MASp69Y3kRYch6 VKjfU5w0TXoF5w2dJAvAkezPPWn7W8+foMCU+ujzJEUEgsFcaoN.OaIQ0QZ7 LpjKx1YR3WNoa3QQL83s.LkGkK3YxFP.t5c2B6KlTIkrWLQFXLA6AldEvO2X Rcsl8iI3viITevDZX26P8Yua3vTeB6PjgcqqOPZPQj59U6ERCqNfp1miMH4M 9fjSeTvGV2aTu7ucFTLEL9N7EAGgXB0msN33CSAGAjpe3w4+GD1IkZF -----------end_max5_patcher-----------
So – looking mostly good:
1 – You should do a 4096 point fft on 4096 points (not a 2048 point one).
2 – You will get a full complex fft (like with the fft~ object)
3 – You are actually outputting 4097 points from jit.buffer~ – for 4096 points you need outputlast 4095
Oh yeah, point 3 I had actually already realized but for some reason it was wrong in this example patch.
Point 1-2: So then I’m getting 4096 bins of data and hence the target matrix should also be 4096 high in this example?
If I were then to progress towards windowing and overlap. Just to make sure I’ve got the theory behind it right:
- If I have a window size of 4096 and overlap of 2, I’d first send to the fft 0-4095 (treated with the windowing) then 2048-6143, etc.
- Continuing with 4096 window and an overlap of 2 – If my total buffer length were say 16384 (4*4096) I’d get 8 frames worth of data?
Yes, yes and yes.
All this seems correct.
I’ll try and make it forth from here.
Here’s what I think would be a test patch for jit.fft analysis with window size 4096 / overlap of 2 with hanning windowing.
Somehow though it’s not giving the results I’m expecting. If you look at the pwindows after the analysis, the left one does indeed show some data, but this seems to be only the phase data (?) because the right hand one (which should be showing the amplitude, as far as my understanding goes) appears empty.
If I could bother you once again (sorry!) to peek inside the patch and see if you understand where it might be going wrong?
Also any other optimizations or observations you may have are definitely of interest to me. For instance, if I feed it a longer buffer – say 1 min long – it gives me the beach-ball-freeze for the duration of the analysis, which doesn’t feel nice. I wonder if that can be bettered.
Thanks, once again, for any help!
----------begin_max5_patcher---------- 1894.3oc4asziaaCD97t+JHVzCIa23vm5Qujjdq.Ms8P.xgff.s1z6pDaICY 5jMIH82dI4H4X6XQQ+PJRnGr1kRxxy7wY9lGj5qWdwU2l+fb4UneC8FzEW70 Ku3B6oLm3hxwWb07jGFOKYo81tZb974xL0U2.WSIePYO+ekqtOM6Nz8xB4yd 1ypt9hD0Xy4eWgbrB9cBohQ3aPAXl4OQQliD8QzaK+NoSrOw7ae+Sh4UOno4 Yprj4R6kdQQZxLzumOaR0kyVMOMalTYERxFemkoew9cHX8uy56Mekp5lwlS9 sKuzb3FOAg2mpFs3SoYSx+zZEsPtTiKIpz7rMTVNNvnehfPyevkGVqpfbn97 BIb6Wc0M5Oqu7dPON19PDgVziQsihv0.eTm3y1.A8H.hL4mz+N+fwfAeVksH Y7GPqkfePU02z6lmnJRevnzaOxKHfC1QANMfHstAD6Hvs57hHiPuL4CRzxUE Rzr7jI2ljc2Rz8IeThllVHmzf4lfQLnQHduVa6AKETK7EBfXnamQbuzYrFav eUamDKp05KUi9t.FFkZvBJy53xIt.lfihkhdH.C47ALJTJJ0ItbiGvCFLU.u OFcjvA7vZc6F54Ddt0I.Y7HqPH+AJJwBTbmjUA3dIYUM.00HJlGc7NXkVPwV VbVrKfQD++NGLJfKwd3eIBFR9Wq9RJBivM5esoelSfJB3l47lcvDsOQ8w3fc 6JkJOyMh3CDXSIDxHjVSFgB1AjQH4LlYyKzO3LEJeJZZgF2W5n.AVfMzKgX0 pHmLC7v5mQ+4jNhV2Vlbmr1YS2jhfpGamIEXHDaMZtXPwIll84QikoyNNboj MLvZKvCcYQvhZc1vyHt7TaPzQ0hJS0EA3UfBdTy4oxBGRlLoNBR3aPAJo4vm rAkiTg9wJ2gC8v6h.ApSrr5lPmVMzvdY5E0En4011xXZEEzNAz3BosL4lJcF HWpoQM6qzYfklPfnUBgSPjOjpc1z+l7Enmq+bsm8uwcGa.qsXbyMrgPacuwy bitJMyLlbxLDAYorYTS6GBNGfWYKZHLndIgydzPGRkBT0fqiOy2JrApkzsKn .2KSLXO8R9v4yEP0OjH6enANqAfG+yqqvxGVTfdt8Hdj3I5OWONe4idzqd8e +O+w0ikyl8F7ae7SM9NOF87zrEqTKQjyoaDjgMMxcRjjdoezYwVAHi8aADns 8BHTWT7WlrXgIF9jDUB5ixBU53jYy9LZZdARkTbmTgpl2gu4rzL4XSIlaFNX eY9DXUeNGhZy.qg3ZTeReq5xZKuNKY1mWl5prZh.RFFnJDTmgQv8MEu0Bgvo kFDwMGBgP5kgPN8USZevBTVI0mUFJrWlbacvBaD5UEo2cmr.kzraCCS+dy0h c2l5AELPGg9SsMg1RXlzogPkJqScm4rWbCsRbljNedhtLGyAhitMbvU5vgtw PHXmIYzO6a+NMvbMhoer5rwz2lB8KjiqMdgPRWgVSJHAj5ZuIoe1qJ2filT8 zQGHLcH2I5DLj5YkMs0CYyf3iKFz1EgaFongTyDF+wQFjZbRgJeQ9rCeiyzL pwfUSIzYVNb7PqELs3dMBfMnqft6bEiMjV89M5b0zoJ8uAhttyUDL9r08pxp MKaRZf6lWMDCHdRb8wTHIamb8wCMtdsA0FVSmWKIFrq+HXmqYAgOj5CZaDej Aa3H2wGIrgFS+sqlNUV7uFNq2oj5jsvd2cvCe8JHklZNK5KnWx5WGmUgbwrj wG4tS.3o3rM1nM0vYwFRTV6ZS0vhweiWMUxlufMG9H2LUCpPdqVJmrToqaFQ NVSHH6cn3OXIWqyHJdPUAHfKKU5r20U.hz5EbFY1DyXmQAcCYv5LWBYjH2IK fGTf1cRUSakgl4oiCgWwBW3BULrLlzdXmjQCzoNNrdfP0K0AMhtsSKVQvtbM 67dGY0By42FuVlupXbkNWYhi9tlLQyXmlA6viueSlRI13ltOcxDo85UB37zI KxSyTkBg.a2iPBLubm2UM.818Ns5qvF2BxJmgaGYk3gvZdkhNDg8DkocvlZj IxgNYagLts6rZer0i5Bgk1w.nGhDizohjvKG3NUjH9LyEzshTX+Sjh6chjOy ajN1iSzKQIZSNbgcKI.2CYx7li0gxDymYNqf2gSc9PVtiiYmHSMM2Q5VSbgW bS3tGmHMIScr8D2G6otkKXG27Z765VabyKUWiychCDmXv1nfPsYtyJKYcqQb Xs4BskiXGbNTjFy.Trk115DsQ9LgGz8FgMMgSNPBDFqr4evlKCW9hnDexypL huI9b.ypBlvHezHa8QwgqGbplfgsPUvgaUvNrJiaOHbyxiCO8p67QKXGHi.g akOJrqTofy+1ifWMZlV2DvfS0zwK8HpaYaY9RRg6WjT7tk3j3AGE8.gIBgYr rpnnp9+SE8BZAe9STl39Lix53Zp8oAMjtsNHtO0bvi5dYh3iL0gow3CqEuaq 4f4SZL6.lstL4SxJ7tM+del5511hR7oxLV2xDP7Bl51JXIdsLE8OQhbJDA5A e6x+Co4ucbC -----------end_max5_patcher-----------
I might try to have a look, but I don’t have Max running on my machine here. Thanks Alex for your tips (and for the convolution workshop in NYC, but that’s another story). Yes, because of the windowing, and also of the necessity to treat the full FFT given by jit.fft, it might be easier to just use pfft~, depending on your timeline with your project :
- if you need to work with pre-recorded files, you could program a routine opening each file in a folder, generating its sonogram (amplitude and phase) at normal audio speed, and saving the result as a jitter matrix file (.jxf). You could even run such a patch with an "offline" audio driver, thus achieving faster than real time analysis.
- if you need to work with buffers that you record " on the fly " , you could at the same time you record it in time domain in a buffer, record it as a " sonogram " .
Yes I carefully considered all the options you described but came to the conclusion that – if I get to work – this all-jitter version might very well be most versatile for buffer based operations because the jxf files quickly become absolutely huge. In a scenario – for sake of example – where I might want to do the analysis on any one of, say, 200 long audio files or a certain part of a file, it would make most sense to be able to do it quickly "inline" as needed rather than to fill the hard disks with jxf’s ten times the size of each equivalent audio file.
So if at a later time you have a chance to check if you can see what’s wrong with the patch I’d seriously appreciate it.
Btw, I’m not entirely sure what you mean with " the necessity to treat the full FFT given by jit.fft". I hope I understood all I need to take care of when working with jit.fft. But I’m sure his will become clear when you see the patch.
Thanks for the continuing help & support!
1 – full FFT – you get twice the number of bins (roughly) that you need for viewing a real FFT (you get all the negative freqs as well, but these replicate positive freqs but with the imag part reversed in polarity). You should only display the first N/2 +1 bins.
2 – This is going to be slow for a big buffer – it’s a lot of processing. You can defer/deferlow to possibly have a more responsive max, but it certainly won’t make it faster.
3 – I *may* be making an external to do this soon – possibly quite soon, but no promises on that or a timescale…
Will look at the patch in a minute, but I don’t have a couple of the objects… (externals)
Out of interest what is the final application?
If there is a lot of demand (apart from me ;-) I might try to motivate Alex on this… so any pressure welcome (as well as bug reports on the convolution/IR suite)
Sure, pressure pressure! :)
Sorry I noticed I was using an own abstraction in my pasted patch. Here’s one without it, so that the only external/abstraction in use is jit.cv.cartopol. I tried to have a go at ignoring the second half of bins but with no better results so otherwise this patch is the same as earlier.
Can’t thank you guys enough!
----------begin_max5_patcher---------- 1843.3oc4a0zbaaCD8r8uBLZ5AGWGU7IoXujjdqyzz1CYlbHSlLzTP1LQhTC EThSxj9au.Xorkcrf.sEWoI4fjCf9HKd3s691EPe83iFbd8U5ECH+N4MjiN5 qGezQ9obSbT63iFLK+pho4K7usAE0yloqLCNCdMi9Jie9+t1bYY0EjK0M5m8 rms50qVNqrZp13+vralrdoY0rz1YmTWYVT9Es+cRGtZ544lB2276ZzEFvRS4 J6KSRnB2eFMx8Ly9L4sselxwdap972+zL4f099qxm4+9G7hlx7oj+nd53AtW 8aGer6oyhDDdeoY37OUVMt9ScXgxamElx744ZX4LXvY1GWa72yBVRc3AQk5W vBtezH5FVw7GxRpR+I6G961VcqzkUyyK9.g2gkpH7d52g.1+ad2rbSS4UNr3 1ihBYj.iHIHUf0CTgM4OvFRdY9GzjEKazjo04iOOu5hEjKy+nlLorQOtW8PT bORjB3QZXODZO.KafN8q1MrL08tz426Rm0QhTocqHDeQv4NrfKRc+QxBALIR 7.FCojT9.hkzEb4rHfGJPU.GIAenJ.7HvDdNui.TWi.4bOWgPwCTblGnjAi6 jfnC1oDNUNZe5f0xfx7AjEYg.FU1OcNXb.Wxhv+RkfG5r7KkDJg1AdyC0+Zc +rf.0HH1rTtcGLUeDn97kFScUGXLrfK8XVqd0cf3N9FD2oD6RQJuvZ+UFR8D xjFKpsnW0jHR7odYL+hcTvHCxzMui9P..6ZaQ9E5uC.3xdLTY33j.Zj42yUT Hq6F.CEdABd+Bqr6KtP2PN4k4lKGVnKmdR9anu8IO4A3JrSPp1PlI.ggmFh2 HFgGT8a9TsC6QBzDacCQkNQNZ6pYEo3AMkcJUxtVBxpvob11SxJPz2pwtRzc ORaWUhr0ZlYB1Z0.kFj0vSQrl4W66nhqKRP0+jhFctorSYge.0JCwfYLH8jR EDOPrlPWuWpmSdt8wocvch+n58R3ts.DmL51a1BiiKP0xXbrGcEgQ7wNEbW+ FR5QmsN.ds8jgIfBjTAaJChn2plS0i422pB3UXCT7XXWPE8GfN5pf5ZXi7+g mDTzuLaG6rnuZdC449moCUO093zh5Embxqd8+7u+4oE5oScJ99MmuySHOurZ 9RyBB6vxMBzOyGEVOH6Ggt+yhu4+b9tLg7KymO2kNdbtIm7QciorHe5zOSlT 2PL4MWnMjU6ZvmbZYktvUS4cROs6yZyR7nhTBYsE.aHaCnBa2VN4FqmtJe5m WT1u0QyTftVHBhhGLMBc2tvOfSgH4sDhrsmBg8yyIAIgyJUxi4nfvTruXH4U ssZHGC2FAkeSS1xB2WZDgA9PxeY4DVlvTcOSDVsjsR2EAa9FtJ2GWNaVtsLG 2SrMz3.19oRGIzXEFiFTjQezn9M0wR6hxpFy91LjegsuZdYJH5J0So.cIap4 krTzAGaP0CAzARSmJChNI35qE3hbrmZlfjCc.ObDIDaqawGG5Pph7FS875on gUqMJBTCt1KoAU4Ho3RtNnumPflYP9S3NWID6kNWMYhwtbI7q6bEiROf5dUa QnsMIMIbyqvOg3dNVeFGhkELVeFt7JKgZM1zgFSR.2XOFM3wOvj+rmeT.2vn v4GYHGx57kSlna9OWLq2YzVwVzN0cPji5yYsTsfE8gYLqF87o4E58UPKHNkT r1MqYCwrPjWcWNUOFrBNW8yhpoRd8BdM7iBGoBQ5yxE5wKL15lIr8GEBzgBE +0d2L1.IJCQnAvkEFq5caEfDqUAynqF6FuwrfX.Yv4L2BYrQgEKPQDztPaBb qDv.Z7joLuVJUv.RbEljIqG1dlz.cpSBGSXRZHnQ0kNs3+B7GWyc90+3sA27 2FuVTuroXkEuRYF4F6XrMhcYEbYMt4M4JkZs2zkkiGqqVu8kyJGOutrxzZDj 2du6dwZStefGa0lx33ZSQXRt5k5hIIET2cZRQksWdvUCdj1ZRL6otF5gH9kH hvlTY3aSrsgSztYSBQq9B37qnsWasrG+tJMBq8Na88NBRigokguMw2lMkfqM EgIwSQ2j15NGtwXUwDjMghqMk1CA9S4qG2G5H2sGjtdFgzGcrC2uAksF6P0Q Bn.NDRF2a4hVAe2ZjD5rMrd8C1EKjsJWQcqUauSQjQ3cmfqDJkHVbBQaJljE 3FwwcfTaGlvMWgLFX5NFNJ1DKFaBO2NQL6cJb26hxlj3FdRDSFLAt7IQROjU 8wZSpX3S3puVDSXbIEeahEiMgHGOlNFHwsNjnrIuB6NfSJgxIkhOxKMLK85A OViMFaEU3iGUXqNJYkI83FGtzwbPc5sGA+T2EV43JXviccDSntrNhssUFHov kHI65QXXrbb0nwiItLtoJ3wPMw0cgkcvgRrzCOSJ4vyjhJzKtxNXwPvY3VQK KpCE3vyjX3pNiQ6Ak0scwdmePErHTRx6XSJXLgy7V098U+6aYo1Ae63+GaGJ V7C -----------end_max5_patcher-----------
OK. So – you don’t need cv.jit.cartopol, you can use two instances of jit.op (hypot / atan2), although you may need to flip imag/real parts in order to correctly calculate phase.
Anyway, as far as I can see this works just fine, but the numbers you get for amplitude are probably much smaller than you are expecting. I had to spill into a multislider and set the range smaller to see them.
Good to hear it’s not all entirely screwed up!
1) "the numbers you get for amplitude are probably much smaller than you are expecting"
Now that you pointed it out for me, I see it too. Why is that and what would one do so they are "exactly what I’m expecting"? :)
2) Re: "you get twice the number of bins (roughly) that you need for viewing a real FFT"
To fix this would one for example create a jit.matrix of size 2048 – with srcdimstart 0 and srcdimend 2047 – between the jit.fft and the jit.unpack?
Thanks – once again. I’d definitely buy you a several beers if I could!
1) You may want to use a logarithmic mapping to db before you display. You should also try with a single sine wave on an exact bin frequency. That should be 1. in amplitude – otherwise you need to redo your scaling somewhere.
2) Yes – but better still use 2049 bins to get the nquist bin too (there are N/2 +1 independt bins in a real FFT.
I think I’m (still) in great need of help to get this right.
Here’s what I’ve tried:
I did a few tests with sine waves at a few of the (AFAIK) bin frequencies and I was getting for example 0.245448 in that bin and 0.122904 in the two neighbouring bins – or in another case 0.176725 in the expected bin and 0.088395 in the two neighbouting bins.
I also was doing idiot tests like putting the amplitude values from the [jit.op @op hypot] through a [jit.op @op * @val 100.] and still got absolutely nothing visible in the so called sonogram jit.pwindow (on bottom right).
Here’s what I’m hoping:
The reason I’d really like to get this "officially" spot-on is that eventually I’m hoping this wont only give me a decent sonogram of a buffer or a selected part of a buffer but that it would eventually also create data for a working inverse fft with [jit.fft @inverse 1] – so that I could do spectral transforms on the data and bring it back into the audio domain.
I’ve read up quite a bit on FFT during this process and the problem mainly is that the jit.fft simply isnt giving me what I’m expecting to get so I’m quite lost on what to do to set it right.
Below is the patch updated for the 2049 bin target matrix.
(Btw, I’ve noticed that when saved to disk and opened the windowing matrix’s loadbang doesn’t cut it, so that loadbang needs to be manually re-triggered… don’t know why that is either)
As always before – I’d be infinitely grateful for any soul ready to take my hand and guide me down this dark path of complex numbers. Thanks again!
----------begin_max5_patcher---------- 2006.3oc4b0zaaaCF9bxuBBicHIK0keKocos61.V21gBzCEAEJ1zNp0VxPht MoEc+1G+PJwNIhh1VVUB6PrAksrd4Ce+74kLe+zSFcc1shhQfeC7AvIm78SO 4DykzW3jxwmLZY7sSVDWX9Zi9Thb7puljNM6qitz94YqkKDR4cqD1enQitT8 G3pxOdUrbxMIoy+XtXhz9MnQnwvKArvH8aDHT+FBGLFd+ckL073xt9Su.Spd RoqWljpdVFQA8vEsRf4pX8E+wompe4ROmSohupdNUODo3ViXNZUdRpDLMKU7 wY4wKEipeBQvXyTHjoeKpbvyOcn7penYYoxT8Or9idSdR7BvumsXpyYq9dJR 9l4dPZb64.AX6AB506kwx7jaAylIkhkq.XvrEYwRBFfgznZ0BT24Gs2Yi5Cn .qhPPfA3XAtvObzQG+vsK9ksB7Z0ewx3Tba.WXtAfnXh9svPWnEhsOnE9mOZ cycqxjsnxEESMnUjKzJrWBVSxVtTjJeBZ8WYR8bEbiHW7pW8JG9mBhLpJbpG ZLQzgl+o0oqhm7Yfu1V6ftSUfJlQ2gychaniNtQZQkGzXvai+r.TrNW.T9ym dcb57BvMweQ.lkjKl5PchyM3QfEOBbqNAGRpS+JfBiX0pHoRHvs9B2jJClYP FJxEvvoGcmMn1CXjfDPhSb4ROfGJeizjH3wLGvCYHElWBt1I.oMtpPH+AJLw .TTm9c3vdoemZ.pKzIMFt+FXk.Cx3.h3LXNK5+eFXDS.dDxCCLFeHYfs9aI. H.1nA1lFZNQJjU2gSZ1Bic78TuOVXWuVJyRciHd.ADS0pXX0qOKBrKkfiZwr Tdi5GVUDd1LfoD7BGIkvJoQf.aNOeZP8qn+bxGQM2JhmKdB.PqmkE2ItZm+H a9qVjgWCXvFR9I+TgJy84yE4fydar7lwSDIKNK9CvqN+78DpHaVTD1I2Cjvi tOyVDpdoIV63ZgECMN9fMk7M3LcVRvPRKJwQnDeCcPgMGjkLnrsxU+rhG4oc 2Y2EGh2nHn.mZM3fdYRH0EN58Fhu0btTxI5jbQrL4gnvOG2KkbCCs.Ak5DOn 8s.SMyT2EsIEvvnlYZAgGZbZVpsn0bDo.z8DnSgQ71.8JIjAYM4PLmLxfGR4 8WwL09mlaE1XSOjwbloOrWFeuUZ5FuzsLzDRGyclv+C80oa64ldlJtcUN30l WgiYWblxu4KljUb1Yu68+8+7GWLQrXgNcuWdl154EnyO+bvqSRWsVV.PsowT HZCOR0FfG0KslZEMFTDbWZSK9HqxTWP42FuZkNj7zXYL3KhbYxj3EKtCLKKG HiymKjfpUd6ctHIULQWW4lgEdtDYrEQQ41H2kEJGUyzG02hbWaM0owKtqHwU sz3xkbagiLm8yFCGHorb3gRXLKrP7HTBB0KCkbLZGDyRhFAF5Q+fB5ksCpNX gLF7tR5Fha1rgdeIg5cAhaxoGTv.dL3OU5DJMgEt1FLnP672PWfUonVF3FZM YdZxxkwpBdzufbvdvdryDBrNRPPmIZzOoquNdKU+rpLxTeMI3WP6GwbXaWLP 1dvGPbwgIpex9jazQ4WsEfm.iZS.0I7vGTT7pSdcW1QGdYkY2CGL2dkBGZLK b716KU3lk2J2LxPHCodPu8dZT8L1XKMhfv1daMxH15G3tYkYH5e+f7bgsMmh hc54JZn44RoRsg9TawvWE+nznMISttZOnCssHaq6tmfiZ1cOhLzb2e85YyD4 +KPJJTO64pRR.PuY8Z2QQLwlVA1IC.7doy+57bkKVsHdhX+bcUVgCGuwtFoF OWjgjiqmpW0PWiuzC5RJAqPiMXjy9dgFTA+VWHlVHUUDB1yb2KIRhZOoH7HW 5QQCpJar3RgLNWWYCPMurWQjNUO1YpUtYk2lEEs5v03NqA3fBzlKjM0zcObV iPF+QLmdkvrgk5jxF6fTavvxc.0Fajk5vF1vhDgh7I2apolU1gZ6L8t94Rfx Ik8R6qSpxbMI1tIiQgNi10sVbFQvzHmGc5EMyC802FPKxVmOoZVWdRe.OLQl pB6kjZ2IGO7cna+ktIY5Tg4yqjukISWkkjJKkAvUO6pquhj9.jznLoOLjcsL gZRlv6lLwrGEKVoO7nH8NnxL5PkVe.P9NJrpx10hGtrRhGFcfBq97eznzp40 rCWt4DOjIVT2KSMoBpC3uKxD0lyE11xJNEpWUMiNToE5gz9nk9iNBB8QSKp6 kIbSxDuakIODIbPmKRMtxg6TQh4iWVNrakofifmeLBtkmeKgROZDeqnB7C1+ g9T4zn+C1NpDRKqIvd7eokkhu0nx2JmylQswLoo0D89idio6QWOg5gINuaSw xKYh1sdBYDeW65PYxmnXcqqPpOUQP51kNhOxDqGJSzt0U.wmPFjtsBPB+HDF 6PkIlO5ScaBsDebOE18hTiUozsdLI9Pn.Mp+ISlLZ2AWA7.ho9MKSB5SMe0n CUZ8JlSGif9.fcpDg8oh.R2lUE1K266Xdz3HjQyx1WKJxdRJ1ZjkrTJEa4z5 fyhF6SHgncb8tpdE6F6VevoqFcnRqOAK513WXezC5V6ETTuCkPA8OQh2+DIl ucMn6xiEQ6egnPdEipayYD4ii.T2FjB4SxPQ8OQh.6exDpikI3QnTsx9Pz98 Zxqt3siEmf4Ty+4CJO0OVgE8jVnnF7iS+OvPdGzF -----------end_max5_patcher-----------