Determining when groove~ reaches end of loop?
I’m working on a sampler which uses waveform~ to let you easily select the portion of a .wav file to loop through groove~. The problem is that I don’t actually want the audio to loop, I just want an easy way to play a fragment of the file once. Also, each time the corresponding button for that sample is pressed, the sample should simply restart if it is still playing.
I’ve been trying to figure out how to do this using delta~/edge and/or snapshot~ but snapshot~ is not accurate enough, and delta~/edge reports a change when the button is pressed (for a restart.)
I feel like this should be a pretty straightforward problem, but can’t seem to figure it out (I’m pretty new to Max.) Does anybody have some pointers?
one way of doing it:
----------begin_max5_patcher---------- 758.3ocyWssaiBCD8YxWgEpOlMBavbYk5Js+A66qpV4DbnzEri.mdUMe6qYL oIokPfTVZjhbvCFyYNyYFO7xDK64xG4k1nui9Mxx5kIVVfoJCV0ysryYOtHi UBKydgLOmKT1SM2SweTA1+UF6ou8islWJEJAKmC25mEorrs2QrNOUjwUvtg2 YTtVs0pydaRY5yvlfIy1ZdESs31TQxeJ3KTFnicz2EQgQO2pQh9ZzM0OQZLf C4769Fwwtx1qSlTMLsiNcNurjkv+fSWpjq5oKSZzkws6xlUpdZE23u11u4aM wFdgUTfqiO7GvG3vl4Cbz4vGyWqTRQOBo3i4HyYhjt3LjP71v5wCt3fywYD7 GzO7Ghs73D9lAQOS5YvE3jo8fanTP360J23Ofby0WuAgm8kn7KSSD5WPWnEB AnEZqzBc.oEM1NCdAOV7RDj7fIA.s32FsDMrUIYEpL4kXoRyQFXGPoPCZqRY 3EdgRiq3FsqTP0XSdxYUkj+bLawldDmbNkPj3GsK+rZrIrNjUsVw9KxYl92k mNjfCMBQ3TN+VyMoCZtIGxLQWgQWQtb4EBHUBasUFuATpLe8xk7hMHEuTgtS JRxdZFKc4WR6.KyjLUm5Gf3BUvH3HCo0ZyRtmCc8.6d9RYQdyEBn0FMr2aDT EIZ2HU3WaUqBykw7VK.9FMzxEYokv+s2d.wHiLsKQgbM+iTpjruxXgLSVX1C zMCmVKoPJumazZ8Tf4NHBr5VGl1mlHB.ZKHn0dq1WgAKPGfDu+yMg2Qk8CYt R45hEaQX8WpLEs68DqYqTASkpOdcuEcvZtMMNlK1+vn7z3UxTgpFCX8Q9T8g lDi2.JhClfCfBxQQUKClbjHem8hft3EQ8yM9rXh1EL4OtXR+1vmBRzwER9cg lBFUL8eHm3ShnvgGQTS1mGjqFsaxmDocISLbzE8mBQ9GjXbofnwii5RsJuQE Q5dDPtm.QzQMpUgHRGPz3wQdCeUABApGf82+DZ+2eBsdxqS9GTZE.AF -----------end_max5_patcher-----------
hope it helps.
I tend to use [delta~] [< =~ 0] [edge~] if that helps.
raja you’re a life saver – I had tried a bunch of things very similar to that, but each one was just missing one piece :)
Thanks a bunch.
I need a solution banging in the end of a loop and NOT banging in the start (i.e. immediately after "startloop" message). Both forward and backward playback cases. Preferably not banging on the stop.
Forward playback: [==~ 1.][edge~] works fine.
Backward playback: ???
Is that possible?
Everything is possible :)
----------begin_max5_patcher---------- 481.3ocwUt0aBCBEG+4Zx9NzvyclB8ht8vR1mikEC0xTLUnAnN2LyO6iK1p6 hoMyZ2KP3bNv424efC6tYjGHiukHA926+jum2NsEOqMiEuZCdf03syKvRaff rJkhy.AG7wpVyqTEDk0Kr1LM2FLOa0sSZh0En5sRhKkfLLaAv+4Z+kX07kT1 hYBxbkKjHT53v.+nnPyDpY73lz.PYM42Z7iaFYl0SActrXjW0v1fphr0R.fj ufr+LUKp17KblhgWaKKviBJt.7KBQRKBQvODDy4JouaiBhz0dqBEZZrYJNdv EJblbea2J5lNEedcRRWvza5hTnHn8F0jAWgdXue33j9QihttZTxT6snjVzHT uqQ4jBEtmtGgttZTXx+zKsxkXIWr2GNtezI3UUmfStyLkN8pcW5kBt9j5mdz vzyKF57fU8RWZXrUSRZ86riGkPithHlQX3rBapB+lf4NCPAk8iuzsjXb7MYT xqDyqKu5x2+DZxIREkgUT8O9mD0WCZIMOmX82T54ToAy7eiyf+.WIcAqICNV QcAqjAGq3tfUzfiEpKXEO3XA6BVnKBqCOMwkkaHB4gS1QjtU1JtvrNMvslxb qcO9ABxFZ8VbICfE59JJcSkJgqc11oo.sGaB0CeBSRzmAB -----------end_max5_patcher-----------
Unfortunately, it doesn’t work for reversed playback.
----------begin_max5_patcher---------- 750.3ocyX1raiBCDG+bpTeGP9bZD1NlO1CUZeCVo83ppUNAGpq.6nfytMsZy y9ZLgjzjTf.3Pu.jw33+yOOyv.ue+ci.yjuxx.Ney4WNiF8t1xHisbKiJMLB jRecdBMybifYqUJo.Ld2Xh0obQBSYFDdjU4Z0YlKro1rjUrlfYTQLv4oxw4Q lkPN6kGfA6WhkT07m4h3euhMWULQrKbh6XGjW9woSKO57jYJ+696xOqOMtwt 0bYZJSn1unJ1ql0B7Skb4COdU9qao4ERgRPSMdK36q3zDvkbUOvwSHi+lYBP zD2JP.h3cDB7MW61IDjxxxnwryQPlFAWF.nZ1vq..mEK7IwAj1.mcwGAF3fI 4GgA1ANIR4RsC6jwTlKcm3fBz6DCFvl1FfAKhfJ.FD62CDSv9qVOWBXzHSde qJgbM.phpKnN.IhodiGpGR49LFwhhYauJ.gZMfFWEnBwsCTAF3D3en9rkHEc V1V6GIkwiE5wubrDF0EFgMzA6aQF83VcUIh8KHUMk5Tjjmod9ThEoTDKQQG7 XIRWnjaPukucqZyyETuegQD62m2ORnaraedH2Vs25dZmtVJ9WGWt04A3jgMC HrMLJzvHHzDsPP1sWX5JSidCU+cAsAPDCfBLoQj9n4taT4AePsNUO9Nfr2hn y2dUartWPzdfZCUQdgGddV9QKjOOa8hErUacTrLkyKRQbxlIT9B62U4BcG9p paqrc8BDXxrgEu3KDYylAhWIk+gU.uKSLbORrcEDGWSyAcnznugY9edWlEqH HgKN6CBY9WyG3DPlIWuZdoKT9MabbOn8HM73BphqqTbzcQ93c8LOJhI9PxTJ OZojKT6TRU6uMVbgMRaChzNkH8j1v5VGHiKeq0vv8+neD8TqH57raKJZTiD8 zgILPupvZ0FdXReLu+V8nKDOPpqYar3gRdMKC+Tu3FF3Uq379ZKM3MWZ9MQZ ACB0BrRoYx9hwjiqLS5mGO2nxK4etfNxybC5S+2.OHO. -----------end_max5_patcher-----------
You can detect the shift with delta~ -> abs~ -> >~ 0.5 It’ll work for ± values.
FYI: if you send the message "loop 0" to groove~ it will continue playing to the end of the buffer. (may be useful if your loop length is always the same size as the buffer~)
Alternatively, you could use a sah~ based mechanism to get it sample accurate.
Do you really need to stop your loop or just stop hearing it? (I ask because those lead in different directions–most of the time it’s the latter)
----------begin_max5_patcher---------- 1622.3ocyZs0aihCE94jeEVnQZkV0IBatjj8gQ69OnR671nQUNAGh63fQfSZ 6LZ5u80W3ZBPftjKRUjhMf+NemK9bNvulNwZE+URpE3u.eCLYxulNYhdH0.S xNeh0N7qqY3T8kYsluaGIRX8fYNA4Ugd7utOIBPE.9lMfW1RhHGHIOHG3OXL fPMmZBr.H1R.jn.4o5+kw4w4OKFMhrluOR+.cyFbCORjR+IQMFDMyNa3XrX8 VZT3SIj0BC9gHe4z.jms5Gnsq5Ge4IfumcSz.MT4qd9yN9VUVfH7N8BX8OIT LKeln86nQLhPK3vxA46E4ilCmMIgqzmOyVMvumNUc3gdxoQjWjX5DJkwwA6H oofTQII0BeXvj3sXhgLrrJj5lnJOME4qtevhEZZqMhxcTHJ3GfVZyT6ew6hY D.VZEskyB.LxFAPC.skGHgFtMefPNIErIguCrhv3uHUPd.AGfWwOPl0ngGZv FdNPGEC5rvyPjZ9zwoE9z492vKF73VbJO4q7G2yRIC0zKkFFIEltL.QKzTFB 5Z7UgcZBBGGSvpvgjjQKY7h7YSYpXVoTdTkqdhENNtxvSpbKJx7Yt9A4+PwP zHyPvhgRHGnG+XkO2DIoHjLx9Di775BeKyjRE3z7aMmwzA0zG7c0+3tnBcIU zgL95ePBpXbHUMwjHZTbBIU5GgEYXnX5.xF7dl3olUr0meCdMo0atQcxDqvD Z.ORAhZ2oZ37kqHVjWUgQeEQ33Ft4TobrOcENQwoqXjJtrRKXNmUepB0nzQ. GQ2gEDA0.VjcwCktKNgZb+KFiDgkOisoqS3LVsGkYlCMLSfTSul7BMPrMyor bF4kSiyUAVEbT.MjjJpOl.GlVejZaSW0DrpGdsw6xSut29WdWEUr5TsXOzGm 81b3y1T1W6u65cr69wt7PmiwSylXm35ipOww6.MIOFYla13yl3Uouec3RGcP Sm4mkKQePtDdq4x.BSfuRrosInp6YYS3cMapWOqQiVLa0f7xO1FqfV1pba2t bWYl7b8zQ8FQ9vrbV8QVQYJ+yJrN1e.kr8.D1xMBUYl1RbesbnluYVHkuOYc tNO2vETWljaJInQE4E7sx3EGcgaoAA02G1r0UpZiPSJG8RmMXLi5Klctavrx UneXFd+vyN8DyJS+QAyfuOsZltVo3CjfmjKgzo7IrPjPWsWXL8qlj9+2LROe FuCHMsFAQGKdaKpLy8UXVVYIE2aCYCNsjDGXgdp1HfCImToGbTaq.xwTUGxT ALZlmbi0EMWTGZw.KpCMZ8Unkpd+y2u.E5Bs0am3rbYIkzVctH+aFkblVsPE .p7BBnxxmXuY5xR5KTizBj9JCtmItl7sbxJE.srqF.fbu+6Yx5s3nPxkvDxw wsBU4MuSlBcy5VmfGFxJhvbhfpKutGwNLUH5fxO1nTB6TVhwIRAWPRdxTodU c+EK5gTQJqi9RzpLCw3XqcQbc5R8CucMqsMZAusZ6EtDDiosq9cFAAZe2EZ8 QF9sO+kgG4zTehu24sFP12+gM0tMvYWtcdgt5PIt9cwTKuYtMskXVp.mHp9x wFkDzLVMP37xcRZK+raW5YxD+EkoTbh.tRtOaODRO2x94nN1jLN+BqbI+L.u tHkfFf5xEyl6oZkuWYaQc8ZFr9Cf1Gy2ED9GROd4eWhJEfPsaoemNmd2LKwV cNIZWSvmffOgtH7hwt07RxZyC08dq.pU62rgj7NPV2t.7LOJj81LLcyPInML NVtcYO7zcWpKzDN2zBWjcmuEwQIFO5CPWufOP1vS1UDIvPTEXPwWVmkM53eX zT8ukjkzBcGOfbxq87nsHcLu5eSpSdFewVhUhZjj7Zjj7GOapvDN+.Iyl5u0 dcvOXxBOLnzFVBM1TdclV4.sobNqMkdUp21WC6cbK8x3vSakmTNgEXskt3Uq yim1AuS6d2IJyg.G6y.GUeOtRvwsGv4bjyNZPLWVNalBB4Z5y0beyNZtEmUt NiF9WL93etAv9Fo.Vd1E.9KGA3Odnww8tBNvdAG6qFdP8w28HPey4GD55Y9. 6q9BdczW8I3.55YOOuOvYw0yb1uG3w+9CNWGimihqzwF0WIiYzclykbkPmAN dWOiG4J4zCzbc3FudnpbuqB67Qi5XxN+nuHTEPN5KA8nuBzS+BPa6q+TtN+d 5+c6DsBH -----------end_max5_patcher-----------
Gentlemen, I want to clarify it once again. There is no problem in detecting shifts. There is problem with looped groove driven by negative sig~ – once you trigger it with "startloop", any detection logic immediately bangs. That is unacceptable. Of course, I could resolve it with some gate mechanism around startloop message, but I’m hoping for an easier solution involving groove’s sync outlet only.
Here is an example, please, take a look:
----------begin_max5_patcher---------- 1213.3oc2Ys0iiZCF84rR6+AKdpUJSjMf4Rk1UpOzmak5ic2V4.NY7VhcD3L yjcUyu8ZaHyvbg.w.4x7BN3vkiO97cke7wOLwYt3AZgC3W.+EXxjenlYhYN8 LS1OwDmUjGRxHElKzY9FoTvclV8ehMxLpTtcMs7w3LmvW5.959+mkZtKw7uc iG7w6ZMQlbKiu7exoIxxaLBFOCNE3FnO56u+3SOI9lULt5cYfAp1rkPnbZyr +2G+fdTMLsyKqDwpUTt7QDJoOX.lyeJEqu4yNu05A83rKDbYA66FN.4pvdyq yv.+ZqyPyugG65DV+EyIqLuXmeMmQxbrlBVQKJHKoulBJTTPya3MrY6ZC4TI BhLjiGVeDE0H431fHXLHGN8d0x50bCMcIcWKVCSOnUA1FhJ.anH2nvmLWNdY j6ojo9zm1APyZlpJXK4p26aSRg8gjBPFRB2BIcJkS8vKZrS6KYOW7Elaz+F7 GYjsy.+1cz7sRMpArBvBFmBVHxAbQ9JRFXs5ZlSR9WvOsVTvjr6n.krX2OCH 7TPgLmvVdqTc82SxSAoToZcyDbPlXIK4IoUl5olH1vkOaWsFG5CsQNgiLzoW jQN4AKG7uH7c2jQml8r1py2p.b33HieajYvOxNWSnSbDNRtLSb7g47sJLGFa XkHiQJN7BJLm89k78NjeIbv40uTS1GKyEh6n6.RZgrUijosXtDzGykPCAE1V BgdmvH41KFPQGRLT457JJUejUast6y+38cp9HqxfsRDbAlpeijiN.g5UBJnl XE.3L.xGAmczDluMDFpTAURXHuvqfhixDjzxJfrvEhaOHoxb8Cbufx8XzJfL 1yNhJ5Zq.Rx7hc1kHKxysObjWYd+gWApoOuS4UBaKK0KkzEXU1MwRozLIwZs DtOrDLpO1aWX47iNXGcqVxWt8h324ITvVwFv5bUHe.SNE7kxf7T991KHx+hC fodPoLhjlsEnYihof6ukkbqtEFa3jjD5ZIYdF8HZAgKztlGWqCDtAvqkNPbi ssfH1FVJFVqADX220MfHxpZNgu6Z+P3A69v40QD86ojjcuUckAGB09nRjB8e Jvp93wsOAGbK54aVrflW1yDv2D7kYamQXKZdWagpN.YKeEDqJgLxqLGViINx EeEjD6P1vITObNdxZ2T4C1DP7keoYC5z+wKHxBwl7j8Tw9O+CnFDSUjGiSz8 9u9Uge9UcKKMkxeV.uUrz0BFWVgDvWad+syfS21O.pUvEd9.WqL2KVAsis.X 3LrxipRqg09Rie7rSLpg8.0tdCKp0s0ocT6ezvFgCz.U2ZC0P0hvb1v.a2NY b4ZIrCMdkiTIXTcxvnPPiCWOHf6kNhZfQiOOdDbGGlCGDNlpT8mWpCv9nUoX kjT6EnLdHtLy3meVoBtZ8MXJXuQZenxRqpQn01GFHXCGGuEmPWYHbubk4gfC pPP+sxFCPOLfqStxPGK1p3vJQZb7vpQ6VfXTOhCOFftaZW+yiLnKo3hNSIfa 5ac6TWr2YBccai06bAutYget7nOJEBDGOp0ALJkb8bLOzUb0oBriN5BtBqka kWTsTqJOoJyp3AMdZzn37GGWK61m78OLrebmbfgfmESv3QgOeEzzSnF9etCQ uXB -----------end_max5_patcher-----------
Double-check, but mine cuts it off fine in reverse. (after the loop finishes playing once through, is what you’re looking for, right?)
You have to turn off the toggle, of course, but it works here. It doesn’t stop the loop, but it mutes its output.
Wow, back from 2010, when i was still ‘Raja’ and was all friendly and shit, instead of becoming…. The Max Anti-Christ! Muahahahahahahahahahaaaaa!!!!!!
Fleee for your lives, Serious Types!
But seriously :p
You’re problem is in the way groove~ is internally coded and you’ll have to create a special solution that gates/skips the first bang on reverse playback somehow.
Attach a scope~ object to the sync outlet of groove~, you’ll notice whenever you stop it, it doesn’t reliably set back to 0, it stays on the very last sample-position(0-1) it played before the stop, which means you generally can’t use any of the detection methods here reliably(you would have to stop reliably at the same position… what they should have done is coded the sync outlet to snap back to 0 on stop, just like the actual audio coming out of groove~ is zeroed on stop…. OR have some way like a "set" message to set the current playback position without actual playback…. FURTHERMORE! if you attach a "==~ 0." -> "edge~" set of objects, to the sync outlet, and also use a scope~ to see the sync signal, you’ll notice it doesn’t have to go anywhere near 0 to create false triggers(i’m testing with reverse playback, that is)…craziness, not sure why that is…)
Anyhooo… where was I? oh yes, create a special solution for that one beginning bang, and you’ll be fine :D
Edit: @Peter, i think his problem is that it creates a false-trigger(even your solution does for me) right when you start the reverse playback…
@Tokyo: I meant that he should solve it at the signal rate with no triggers at control rate. (or the timing of the triggers at control rate shouldn’t matter)
For the ==~ issue: you may not be seeing the full 0.0000000something_else because number~ truncates its display to fit. You shouldn’t count on it going back to 0 at the start of each loop, since these type of incrementors (0-1 like phasor~) often look something like this in C code: (assuming that x initially was 0)
x += phase_increment;
x -= (x>=1); // wrap when reaching 1
x += (x<0); // wrap when below 0 (for negative phase_increment values)
(x –> delta~ —> abs~ –> >~ 0.5
will reliably indicate a transition from the last sample to the first (if forward), or the first sample to the last (if backward). You can adjust the 0.5 value as you need to; really it just has to be greater than the phase_increment value, and that will take care of starting and stopping at weird places. (You’d have to calculate the phase_increment value, but it’s not terrible. You could just do it via a sample and hold and a delay (so when it stops changing, sample and hold the delayed value from the previous sample). Alternatively, you could use some slightly larger value like 0.01 (assuming that your loop is always going to be at least 100 samples long, easy enough to enforce that))
The reason why this wraparound behavior happens has to do with interpolation between the end of the wavetable and the first sample. It doesn’t make as much sense when you’re thinking about a large buffer, but when you’re dealing with a waveform for an oscillator, it makes a bit more sense. Resetting to 0 works fine when your wavelength is an integer (in terms of samples), but a lot of frequencies aren’t. Middle C has a wavelength that’s 168.561508 samples long, for instance. Since we have to process at the single-sample level, it means that about 56% of the iterations through that phasor (0-1ish signal) will be 169 samples long, and the rest will be 168 samples long.
I’d also add that this is not an MSP-specific thing; this is common to all DSP code. The sample-rate is constant, so you have to make compromises to make things work. You also find out that there are some things that you can rely on, however, and use those solutions in place of others that seem like they should theoretically work.
Anyways, this is an overly long explanation (and hopefully not over serious), but there are reasons for these behaviors. If they still seem odd, I’d offer the following strategies:
1. If you keep things in the signal domain as much as possible for synchronized code, a lot of problems disappear.
2. Only convert from signal to control rate if timing doesn’t matter.
@Tokyo: Thanks! Your guess on my problem is correct – it’s false-triggerring "loop end detection mechanism" on the reverse playback. And I trust you about filtering the beginning bang as the only solution. Awkward. Alas.
@Peter: Thanks for paying attention! Seems to be we play in different leagues and just don’t get each other. I can’t stay in signal domain all throughout the code. More than this, I’m sticking to scheduler, message ordering and simple control logic. Pretty sure I’m mostly hammering nails with microscopes, but it works to the moment.
Guys, I’ll ask you two personally to check my device when it’s done just to get you laugh out loud.
"You shouldn’t count on it going back to 0 at the start of each loop"
Ya, i remember this is true for phasor~ and the like.
"The reason why this wraparound behavior happens has to do with interpolation between the end of the wavetable and the first sample."
Ah, good explanation, forgot about these applications of the idea.
But aside from Empytree’s issues, my personal issue with "==~" was not so much about the sync-signal not reaching 0, and more to do with the "==~" detecting 0 from the sync-signal where there was no 0(scope~ showed the signal not even nearing 0)…. but this is a moot point since i was only trying to help, and don’t need this to work for myself… i just don’t like it when scope~ shows me one thing and the detection/conditional-signal objects react to something else which i can’t see or snoop anywhere :p
But cool, Peter! Thanks for reminding me about why it never reaches 0(and that’s it’s true in most environments, i’m rusty on Max/MSP these days because i’ve switched to SuperCollider, but SC also has similar sync-signal behavior, albeit a bit more easily and reliably dealt with using other objects available).
Post it up when it’s done, it’s often easier to help someone debug a finished idea rather than one that’s still developing.
@Tokyo: The other thing re: scope~ is that scope~’s display isn’t sample accurate; it’s showing you a group of samples, so there may be a 0 in there that isn’t visible. Agreed that this is less than desirable behavior.
Plot~ can show this, however. Here’s an example with a square wave at the Nyquist frequency: (and an example of scope~ not showing it…)
----------begin_max5_patcher---------- 764.3oc0WssaiBCD8Y3q.gz9zlDg4Vnq18g86XUTkw3l5VvFYb5lzplu80W. BogPnn1nt4AmvbFO9Lmw1C4EaK2T1VbkqyOb9iik0K1VVZSJCV0Oa4V.2hxg UZ2bQrhBLU3NyfIvaEZ6+b9bmxblXeCxcLpfBKvZzeyIv7VD95TkUuEd0Vna JHzbrPuDfNAnh7rN..+t9x1HZbtwZITftmPWeKGiDl7ILNTNIm.e0bchhTi9 x0zYU8bHYZtwReXNv2UY6Uaa0vrQpERpjh4iHiqHqONgKXYZ276S.7GV.J43 JYE.JHLZmzEDAVDK+rzWlyI5T2qdnMiOV6ZVGiIwtRrIRJ5RUj2w8tbFTF+U mWkAFgsdEihGTk89+Qk+Ljp3jCUnvkWVutYRxE9ux4dx4SYlKcaDp3zEovKK RuUtdWaw.ZwJ1aHIKYJRF94LHZ+fBvnu0IxWWX8iApuBiZF6irK+.queaui+ mYwEbgh6PEP+njNZRPxPEv3OPMQRs8Nf2op.txpBHTugNLXHUI5CTU99u1+U eihmuoy8hnyKIgSQRN5MT5srOxjYvzHzybgkm4Ndulw9Rif1tWaRUrq8kwZy .IFhky3F.uEgyZFVJkGvgvpJx2SPORwlrMnoBoXIiPE2VI1kaJ1HBGI+YKdN gh6.y3j0D5AXSO3NNPYzNy9NRt.y6AHiU.IT47fbwQ8lOfgoZw.bJxgUSwNH +jvV.4Oh40JVGUnFNGlhyOEkCoqw8SICTOLpYNmiPF7ywGC5YniQpuc6a4Rs 8c01Mle01Y0D11WgXk3gavgf4HDaCULotd0GbqaQCB7Z+pcOuVDLdOWZ2r0M p2WSr6IasCZ89M+MEMKT1ONuqXa3nlSolFJxiJsKSFtRPn52ctiOAG4y8jrL LsaFmQpfo4XME85U+GKaRFAajul70jNfKPmatZrYLkpjuTrAb0XS3HXS7UiM QifMgSjMlS7vxxmj2kVGRMQj2o8foMX7L8iDp4QcDc43mHM9mXqh1q1+CHXr d6. -----------end_max5_patcher-----------
Thanks, Peter, did not know about the new Max6 plot~ ’til now. And this reminds me: there’s the old object capture~, too (i had even forgotten what it was called :p …but glad i finally remembered, though, plot~ looks much nicer :)
"You shouldn’t count on it going back to 0 at the start of each loop"
Am I wrong or it may also never reach 1. ??? I think I had noticed this in a device I worked on.
Stephane, you are correct: it MAY also never reach 1, mainly because of what Peter wrote:
"The reason why this wraparound behavior happens has to do with interpolation between the end of the wavetable and the first sample."
If however, the situation arises where the interpolation between the first and last sample just happens to avoid truncation/rounding issues, it’s still possible to reach either 1 or 0(just not reliably for every case of looped-length).
You can test for either case via ==~ into +=~ into number~. (It depends on how the wrapping is done for whether you see 1, but I would expect not to see it as an exact value, since that should wrap to a phase of 0.)
That’s what I meant. Does it have something to do with rounding off the values also ?
You’ll typically see the phase incremented and then wrapped.
dx = 1/frequency;
x += dx; // increment phase
// Generally, only expect a 1 for output if output happens between the phase increment and the wrap
// There are several ways to wrap:
x %= 1; // Modulo, problematic because of negative values
// (could add some very large positive integer first)
// (also presumably involves a divide which may be inefficient)
x -= (x > 1); // These only work when dx can’t exceed ±1…
x += (x < 0); // …(Could happen with FM)
In gen~ you can also use wrap. There are faster ways to do the wrapping via bit-manipulation, but those are not accessible (afaik) in gen~
Hi to all. I’m a rather new Max user. I encountered the "not able to get a bang at the end of loop when playing backwards" problem.
Here is the simple solution I made up after two hours of pulling my hair off:
Just use 2 groove objects ! Send to both of them the same min loop, max loop, startloop, stop entries.
Of course, one of them will get the playback increment (let’s say "x"), and the other one will get abs(x) as playback increment.
In other words: Get two grooves objects, have them groove the same buffer, with the exact same parameters, excepting the fact one of them will alway play forward.
Use one to get sound, and the other one ("forward") to get the bang you need at the end of loop (when reaching "1").
I expect that if you run this method while grooving a veeeery long buffer, there might be a slight delay between both buffers, but who would want to do that ?
Hope this helps.
^can’t tell for sure without seeing your solution, but if that’s what you did, you could also just use one groove~ object and take the signal from the sync-outlet and only send it through a ‘!-~ 1.’ object when in reverse(that changes a ramp moving from 1 to 0, back to a ramp moving from 0 to 1).
(this may cause extra bangs if you switch from forward to reverse in the middle, depending on how you’re getting your bang, but the same would happen anyways with 2 groove~ objects i’d think…)
anyways, just something to try, thought i’d mention since i know this feeling: "after two hours of pulling my hair off" ;D