Selecting time ranges from the date output
Hello hello
I'm building my first patch based on the date object. I'd like to split triggered events across time ranges in a day, e.g. during 13:23-14:08, send things to X, during 14:09-15:19, send things to Y, etc.
From unpacking and printing, I see date can output a list of three integers corresponding to hour, min, sec.
I was thinking I could use the split object to set time ranges and inform relevant parts of the patch. However, split needs single integers for its range arguments.
As such, is there something I should use to convert these values into one integer? E.G. 15 00 00 would become 150000. I could then set ranges, e.g. 150000 152348, to cover time periods.
Hope that makes sense! Perhaps there's a more efficient way of doing this, I'm just extremely new to Max (i.e. 24 hours in).
EDIT: I've played with sprintf, but just realised date's outputs don't use double 0s. Combinations therefore result in, E.G, 15:00:00 =1500 vs. 15:23:48 = 154328, making my range idea null.
As such, any ideas on how to split date's output into ranges would be very welcome. Thank you!
Hi Steve, and welcome!
The easiest thing to do would be to convert everything into seconds, i.e. (hours * 3600) + (mins*60) + secs. Alternatively, you can use translate to covert from hh:mm:ss to ms although that will require dividing by 1000:

Using translate makes it easier to convert back again as well although you will get an extra integer in the output message for the additional milliseconds:

This is so helpful, thank you
You're welcome. That's why we are all here!
Translate is great, cheers for this. To avoid too much calculation in future, I'll probably try building an interface of some kind using sliders to set time ranges for a 24-hour cycle. Then I can get a quick visual reference of what things will be happening at what periods of a day.
As someone coming from DAWs, I like this domino effect of finding one thing, then realising you need to/can build something else useful straight after.
Yep, that should be pretty straight forward. Max has lots of visual interface objects, such as knobs, sliders, buttons, selectors, switches and so on, that you can configure and string together just like other standard objects. They are all along the top tool bar in the patcher window.
Also take a look in the left-hand tool bar for the objects tool where you can find shortcuts to every object in Max:

And it's well worth going through some of the numerous tutorials and help files whilst you are finding your feet.
If you can think it, Max can do it!
Except for text strings! Max is rubbish at manipulating text strings! ;-)
Oh, and with reference to sprintf, there are formatting codes that will ensure that single digit integers will be output as double (or more) digits with a leading zeroes. sprintf in Max is actually ported across from C++ so for a full list of formatting codes you'll need to Google the C++ documentation. However, I can tell you for free that %.2d will insert two digit integers with a leading zero if required.
Oh, and for your controlling your time ranges, have a look at rslider, highlighted here in blue in the top toolbar:

Cheers Andy, am ploughing my way through some great tuts on YouTube currently.
As for sliders, I've built prototypes scaled for seconds, minutes and hours, to be dropped in and refined later once I've got things better underway. Nice to have resolution options, depending on where the project goes.

On the subject of sprintf, thanks for that. Last question – with a time-based piece, do you think I'd need to worry about the hash table filling up, as per this discussion? It's admittedly a 16-year old thread https://cycling74.com/forums/how-to-concatenate-strings
I'm not particularly aware of what a hashtable is, but wouldn't want to cause issues over long durations if lots of messages are flying around.
Thanks again for the help
EDIT: Actually I could probably nest range sliders as necessary later for specific events within a timeframe...
If you are constantly creating new symbols that can become a problem (slow down) on long running installations. But time values will repeat after a while so that's not a case of always new symbols. Check symbol table size with this message: ";max size" it can take hundred thousands before you will notice any negative effect.
Good to know, thanks
The issue with overblown hash tables is really all tied up with text strings, and as I hinted before, Max is not built to handle complicated text strings (even though it can with some imaginative jiggery pokery). Lots of constantly changing strings generates lots of unique hash table entries. But as @11Olsen says (and he’s a VERY wise owl to take note of) your case will probably generate a finite number of recurring symbols.
A lot of the thread you mentioned mainly related to OSC which generally uses “text” strings (or complex symbols) to transfer commands over networks. Fortunately, most devices have a finite number of OSC commands that get reused over and over again but those pesky Arduino and Rasppi nerds can create their own languages ad nauseum! Personally, I doubt if you‘ll ever run into that problem.
Your rslider prototypes look great but be aware of the factoring - your second prototype is actually translating 24 hours into 24 minutes (or something equally odd) and the last prototype is translating 24 hours into 24 seconds! You need to be factoring by something like 1440000 and 3600000 (although it’s way too far past my bed time for my tiny brain to be mentally juggling with big numbers greater than ten!)
Talking of @11Olsen, you’ll tend to find a few names cropping up regularly on here. He’s definitely the best I’ve come across so be kind to him!!! He’s a whizz-kid at condensing 43 overly complicated steps down to three simple objects. 😂🤣😂
Thanks Andy. But there are many people here full of knowledge. Although, I know many that have become silent over the last years. Maybe went on doing other things or can't spare time anymore to post regularly. Or have found another place to chat about Max?
i see no need to not leave the data type int here.
@andy thank you, that's really helpful, and especially for the rslider spot! I'm sure that would have driven me crazy at some point. I'll do some tinkering to figure it out.
@11olsen appreciate your knowledge, thanks v much
@roman which patch are you referring to? It might be something I've left in as a visual ref for myself while I'm learning the flow of things.
I think @Roman is perhaps referring to the $ix wildcards I used in my first reply??? Using $fx (for floating point maths) would work too but personally I don’t see any advantage for what you are trying to achieve.
I liked the idea of selecting a time range in a day so I made my own version of your patch, involving only one rslider (actually a second one is almost hidden) and a radiogroup to select precision (hour/minut/second).
You can also manually edit values and rsliders are updated accordingly.
The only bug I found: when manually editing the end range value, minutes/seconds don't wrap properly (you can set 13:72:00 for example instead of 14:12:00). What is strange is that the start value does not have this issue.
EDIT : I uploaded the code with the fix (see post below). Also I added a [loadmess 0] on top of the [radiogroup] to initialize the patch properly, and removed a couple "set $1" messages that were absolutely useless.
Wow, thank you! So nice to see a random personal project spin off into new tools from/for both me and others. The precision scaling buttons is such a useful idea and the rslider responding to manual changes really helpful. I'll get under the hood of this to try and understand what you've done.
Would you mind updating here if you find a solution to the bug?
Sitting in my bed having a lazy morning and trying to remember how to count up to big numbers after 10, I suspect that you might have forgotten to use mod division (%) somewhere instead of normal division (/) and not carried the remainder over from the seconds to the minutes. Just a though before I crank up the rubber band on my Windows PC.
I've wound up the rubber band on my laptop and had a look at your patch and found the fault amongst the plate of spaghetti! (Sorry, I'm not being rude but I have a touch of OCD when it comes to wires (aka patchlines on Max!!!)
The problem is that when you update the upper range value of the rslider using the number selectors below it, it does not generate an output from the rslider to feed that upper range value back into the calculation below it. That is allowing your number selectors for minutes and seconds to roll outside the range of 0-59 and not carrying over or under to the next number selector on its left.
So you need to add a link with a bang button or t b object in it between the output of the righthand number selector above the middle rslider to the left input of the rslider - that will force the rslider to output updated values from both inlets. Then it works:

I can see that you have gone to some lengths to avoid infinite loops occurring in allowing multiple ways to control the values that all feed back on each other. However, I suspect that it's adding a lot of unnecessary complexity and duplication that you could eliminate in various ways.
I'm glad you like it, and thanks for the fix! I missed the need of that bang in my rush doing this patch and posting it here.
I realize that in most of my patches I always try to create different ways of controlling the same data, but in a way that every inputs are updated accordingly to avoid value jumps and for UI consistency, and I often end up with a spaghetti plate and a lot of [prepend set] or "set $1".
There certainly is a way to organize objects more nicely but I'm not sure there is a simpler way to solve this problem. Actually at the end I always think that this problem is the wrong one, because I always end up overcomplicating control without asking myself "what do I really want to do with that patch and which controls really matter to achieve that goal?".
For example in our "day period selection" patch, depending on the context, the manual input could be plenty enough, but in some other context the rslider might be preferable.
Oh and about the modulo operator: nothing to do with the issue you fixed, but I actually started by using it (instead of the [expr]) and could not get it to work properly so I ended up with my odd [expr] which felt more logical at the moment I did it (I was in a rush :-P).
I'm pretty sure there is a more elegant solution though, involving a [%].
I've dug the same hole for myself in writing a clock, alarm clock and timer module for my project. I'm using the same set of controls on my control desk (buttons, knobs and digit display) to control all three as well as having a duplicate interface on my Max patch that uses number selectors, display windows and control buttons. Getting them to all to marry up without colliding or sending Max into an infinite loop was a nightmare! Joining this discussion has certainly given me some ideas as to how I could improve what I've done.
Depending on how your patch is structured, using the pattr system might help keep everything well organized without too much patchcords. For example you can get a "data" patch with all the values you want to control (using scripting names or [pattr] object] then access those values in some "control" or "UI" patches using [pattr @invisible 1 @bindoto whatever] (to retrieve the whatever value] or [pattrforward whatever] (to send a new value to whatever). It takes a bit of work to get used to its own logic and does not necessarily avoid infinite loops but helps a LOT for patch organization, plus it help structure your data through subpatchers, store them independently and/or all at the same place through [pattrstorage] and [preset], then doing fancy interpolation between presets.
Another approach I found for the "multiple controls, one data" problem is to control the amount of data change rather than the data itself. This way data control and visual feedback are separated, so no risk of an infinite loop! I hope it makes sens without example patch. This approach might not fit every use case but I found myself using a lot when I found it.
(It's going totally off-topic sorry for that).
I found that trying to use pattr and scripting names gave me strange dreams at night! I've never managed to make them to work yet. So I use good old fashioned patchlines and a few send and receive objects, albeit with meticulous (obsessive) attention to tidiness so I can then trace where everything is going. My brain is getting a bit too old to cope with virtual links that I can't see and "probe". My mega-project now has some 1000+ threads running through it and the only way I can keep it all under control is to see it in black & white!
Just to let you know that I updated my patch in a post above.
Cheers!
Amazing, thanks so much! And to Andy for the tech support.
I annotated the guts of the last version to myself yesterday as best I could, and think I should be able to get my head round it soon enough.
However, I was having trouble working out which rslider to use outputs from if I wanted to send the range as a value in seconds, i.e. upper value in seconds – lower value = total selected range in seconds.
Would it be the dark rslider's outputs? I think that's outputting in seconds prior to conversion into hh:mm:ss for the UI, but I might be wrong there?
Here's the next step I was building in parallel to this, btw, starting with an idea from this thread: https://cycling74.com/forums/bang-if-two-lists-match
In this, once the start clock times match, a state is activated (in this case just the toggle switched on), and when the end clock times match, it's deactivated. If using your patch, I'd be feeding the output from your rslider to help dictate the start/end times. I wouldn't need the overall seconds range for that, but it might be useful for other applications.
Please excuse how janky and inefficient this is bound to be at this stage lol
Yes, I’d use the outputs from the lower rslider and subtract the left output from the right output as you suggested.
Brill, thanks Andy
@Steve, have a little think about this bit of trickery:

EDIT: If you think about the logic you have used, The state won't change correctly if the clock happens to start between the two values set for your range. Also, it might not change correctly if you adjust the range whilst the clock is running.
@Steve, as you asked which rslider to take values from in TFL's patch:
What he's done in his presentation mode is to overlay the top rslider on top of the lower one. The top one is used to set the values in the bottom one according to whether the required accuracy is in hours, minutes or seconds (clever!). By making the top rslider transparent with a subdued colour for the control bar, it makes it look like you are actually setting the bottom rslider directly. It's a neat trick that I've used before in my clock and patch selector routines as a means of displaying the real "live" values whilst isolating them from direct user control (and also avoid infinite loops) by having an identical but transparent user control lying over the top.
@Steve, expr objects are a good way to compact lots of calculations:

However, I was having trouble working out which rslider to use outputs from if I wanted to send the range as a value in seconds
@Steve: In my patch you can find two [outlet] objects. They both connect to the underlying grey rslider (one for the left outlet, the other for the right outlet) AND to the corresponding manual controls. These are the connections you want to use to get the range start and end in seconds, regardless of how you edit the time period (with the rslider or manually).
For the seek of better UI, you might want to
1. Create a new patcher with my code above
2. In the patcher inspector, select "open in presentation mode"
3. Save this patcher as "day_period_selection.maxpat" in a folder monitored by Max
4. In your main patcher, create a [bpatcher @name day_period_selection.maxpat] and then simply use the two outlets of this objects to get what you want.
@andy amazing, thanks so much – you've actually also noted something I was also finding with the patch, which was that if you replace the toggle with a button, it bangs twice because the metro relays the time twice when set to 500. It was on my list of things to try and work out. I hadn't even considered the time states you've listed there. I see how that expr works now. Cheers for outlining TFL's patch too!
@TFL thanks for the guidance, really appreciate that!
@andy still marvelling at the simplicity of that expr to trigger the state change, ha! I'll practice my maths and spotting what can be condensed down into expressions that I tend to think about visually
expr is an incredibly powerful object once you realise that it’s not just for doing maths. I used to do things just the same as you when I was starting out until I saw examples on here of how expr can be used to tackle all sorts of things. There’s a chap on here called Roman who relishes turning almost any into expr statements!
@andy @TFL it's already becoming a thing of beauty to me
Whoops, just remembered the whole bpatcher part prob won't be included in that. Here's how it's looking now though, for ref, and it's functioning great so far.

Depending on it’s purpose and whether or not you’d want to use it in other projects, there are options in the inspector that can be used to force bpatcher code to remain embedded in the parent patch like a regular patcher rather than residing as a separate file on disk.
That makes sense, cheers
Sorry to resurrect this thread, but something in this patch is buggy and I cannot for the life of me work out what's causing it.
You'll need to replace the soundfile in this, but fwiw I used a woodpecker sound, which has been driving me even more nuts while troubleshooting...
So I've used the time range selection to feed a sub patch. The sub patch staggers X amount of bangs over that range randomly to trigger a sample. Thus you could say, I want to hear a woodpecker three times between 3pm and 4:47pm, but when it sounds will be at random.
The patch process is:
Select a target time range
Select the number of times you want the sample played
At the correct time, the state becomes active, the bangs/samples occur, then the state becomes inactive.
The bug is:
The state toggle is randomly activating and deactivating outside of the selected timeframe. This then naturally triggers the last set of parameters.
You can see from this example in the console that the first three samples triggered fine: state activated, 3 woodpeckers, deactivated. However, it then bugged and the state went active and inactive immediately, triggering 3 further samples over the playback time. This usually happens one to two minutes later.

Any ideas what is causing that state to activate and immediately deactivate in my current setup?
Thanks so much for any insight
There are a few things I can see that are causing problems:
1) Don't forget that the expr object checking to see if the time is within the selected range is generating output 6 times every second even if the visible toggle indicator doesn't change state. This is because you have the clock output occurring twice a second and then as the hours minutes and seconds all bang the expr calculation you get three outputs twice per second.
2) The quick flip in the state occurs one minute after the state has become inactive. This is because the clock changes the seconds back to zero BEFORE it increases the minutes by one as the outputs of of your Time patcher are coming out in right to left order (the Max idiosyncrasy). I'd suggest that you only use the seconds output to trigger the expr calculation to overcome this but even then you will have to be sure that the values from the clock routine come out in the correct order.
3) Once the state has been momentarily triggered, there is nothing else to turn the sample playback routine off. Your send bang_inactive object doesn't connect to anything. Once the playback routine has been triggered again, it looses the plot!
Hope that helps!
1. Yes, I thought this might come back to haunt me in some way and have been trying to keep an eye on it.
2. No wonder I couldn't figure this out! I thought it had to be something to do with the clock itself, and that was truly beyond me. OK, I'll delve into this a bit further and see if I can get round it somehow. To be honest, the change state is mainly a UI thing for monitoring it, so was considering just going straight from expr, but really glad you could explain that.
3. Tell me about it, lol, it's been maddening. I'm going to be replacing that whole crude playback system with something more sophisticated and controllable in forthcoming iterations.
Thanks as always Andy!
Just do this:

There is no need for all the triggers in there as all three values are being output every two seconds and the expr will be triggered by the last one out.
Oh you meant that expr, sorry, I get you now. I must have just copied the other ways I used triggers to get the calculations to update the range, since they aren't triggered by the clock, and put them in without thinking. I'll give this a try, cheers!
Sorry, I didn't make that very clear, did I? It's getting late!!!
And doing it this way will only generate two updates per second instead of six.
This is great intel, thanks Andy, appreciate it