# Faster-than-realtime sonogram creation in Jitter?

Hi there!

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!

antwan

Hi Antwan,

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!

Hi there,

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.

Thanks!

a

###### Attachments:

Hey,

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…

Alex

###### Attachments:

Hi,

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.

a

**all**of the following text. Then, in Max, select

*New From Clipboard*.

```
----------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

good luck!

Thanks Alex!

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?

Thanks again,

a

Yes, yes and yes.

All this seems correct.

A.

Cheers!

I’ll try and make it forth from here.

a

Hello again,

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!

a

**all**of the following text. Then, in Max, select

*New From Clipboard*.

```
----------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 " .

All best,

Hi there!

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!

a

So,

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?

A.

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)

p

@Pierre

Sure, pressure pressure! :)

@Alex

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!

a

**all**of the following text. Then, in Max, select

*New From Clipboard*.

```
----------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.

A.

Cheers!

Good to hear it’s not all entirely screwed up!

Few questions:

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!

a

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.

A.

Hello fellows,

I think I’m (still) in great need of help to get this right.

Here’s what I’ve tried:

1)

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.

2)

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!

a

**all**of the following text. Then, in Max, select

*New From Clipboard*.

```
----------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-----------
```