12 messages
Open this post in threaded view
|

 From here, I'm moving the discussion to sc-dev. http://new-supercollider-mailing-lists-forums-use-these.2681727.n2.nabble.com/Pspawner-and-Rest-tp7636556p7636605.html(At this point, it really became more of a dev topic. Also, it's a new topic, not really a reply to the original thread.) RJK says: > The more I look at the use of asEvent in relation to Rest, the less I like it. > > As far as I understand, it exists to allow EventStreams to consist of both Events and near-Events (SimpleNumber and Rest). > > But this always has the potential to break filtering: > While this works: > >         Pseq([(), 1, ()]).play > > this doesn't and never will: > >         Pset(\dur, 0.3, Pseq([(), 1, ()]) ).play Hm, currently, this example breaks because Pset does "inEvent = evtStream.next(event);" instead of "inEvent = evtStream.next(event).asEvent;" But actually, "never will" work is an overstatement. After making that change to Pset: p = Pset(\dur, 0.3, Pseq([(), 1, ()])).asStream; p.next(()); -> ( 'dur': 0.3 ) p.next(()); -> ( 'dur': 0.3, 'delta': 1 ) p.next(()); -> ( 'dur': 0.3 ) So this particular point is not really an objection to asEvent. > Also, the current implementation is incomplete. > Right now asEvent is invoked in: Ppar, Pfpar, Pfindur, Pstretch, Psync, and Spawner, > It is not used in: Pgpar or any of the other filter patterns. > This is a bug waiting to emerge that would touch a lot more patterns to fix. *That* is the correct diagnosis of the above Pset problem. > IMHO, EventStreams should stream Events and only Events to guarantee consistentency. Now this, I totally agree with. It's an accurate diagnosis and it points to the solution. The problem is that we reuse the Stream concept for both data and event streams -- making it the caller's responsibility to convert as needed. Because it's *every* caller's responsibility, we missed many of the potential callers that expect events (the incomplete implementation). The casual mention of "EventStreams" points to a better approach. We don't have an EventStream class now, but if we did, it could be a stream wrapper that always yields either an Event, or nil. Then patterns that operate on events could do mySourcePattern.asEventStream instead of asStream, and not have to worry about conversion after that. > 1. A version of Event::silent that is syntactically consistent with Rest? >         Erest { *new { | dur, inEvent | ^Event.silent(dur, inEvent) } } > > 2. The more wild eyed possibility of a Rest wrapper (call it RRest) derived from Event instead of AbstractFunction with 'value' redefined to return the value of the Rest at its 'dur' key. Hm, in both of these cases, the user would be responsible for knowing the difference between rest-as-value and rest-as-event. I don't quite see that as an improvement. The user should just think "rest" without having to worry about subtle distinctions in the implementation. > you would need to copy and paste in the entire Operand/AbstractFunction interface That in itself is a pretty significant objection to the rest wrapper idea. I think introducing an EventStream class would be a much better way to go. It would be transparent to the user, and, for any developer writing a pattern class, it's easy to explain the difference between asStream and asEventStream. Proof of concept: EventStream : Routine {         next { |inval|                 ^super.next(inval).asEvent         } } + Pattern {         asEventStream { ^EventStream({ arg inval; this.embedInStream(inval) }) } } In Pset:                 var evtStream = pattern.asEventStream; And the above example works. hjh _______________________________________________ sc-dev mailing list info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspxarchive: http://www.listarc.bham.ac.uk/marchives/sc-dev/search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/
Open this post in threaded view
|

Re: What to do about asEvent?

 > + Pattern { > asEventStream { ^EventStream({ arg inval; this.embedInStream(inval) }) } > } > > In Pset: > > var evtStream = pattern.asEventStream; > I like it. It is much better than putting asEvent wherever a value is taken from a substream. And it would clarify what patterns define Event streams only.  (It seems to me that a search for invocations of that method would give you a more or less definitive list.) But I continue to have this nagging belief that reengineering EventStreams to be Event filters (e.g., that always return the Event they are passed) would simplify and improve the whole Patterns library. (In particular, it would simplify the current mess with resource allocation and clean up)   So, from that perspective, I would prefer to enforce the distinction with Rest and ERest. I suppose that is a kind of oddball software purism.... Cheers, RJK _______________________________________________ sc-dev mailing list info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspxarchive: http://www.listarc.bham.ac.uk/marchives/sc-dev/search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/
Open this post in threaded view
|

Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 HI James and Julian, OK, here is a completely different approach to this. The fundamental problem here is that some objects being embedded in a Stream (SimpleNumber and Rest) need to know when that Stream is an event stream. Right now, Event streams and value streams both get passed an Event as the argument to next. Instead, value streams could be passed  an instance of a derived class EvaluationEvent : Event {} Then, when Rest::next gets an Event, it would know to write itself into that Event's \dur key and return the Event, since it would get an EvaluationEvent if it were being used as a value pattern.  So that would loook like: Rest::next { | ev | (if(ev.class == Event) {^ev.put(\dur, this).yield } { ^this.yield } }  Searching on patternpairs only turns up Pbind, Pbindf, and Pmono as patterns that would need to be altered. (Proxies use Pbind internally.)  Perhaps there are other classes that do pattern binding as well.  If so, I am hoping you guys might identify them. While streaming, these all make a copy of the input event: event = inevent.copy; to allow the untouched original to be returned if a value stream ends. Instead, they could allocate a single EvaluationEvent outside of that loop and do: event.clear.parent_(inevent) Then, if none of the constituent value streams terminated, they would return  their event in this manner: inevent = inevent.putAll(event).yield; This would entail the overhead of copying the EvaluationEvent into the Event partially offset by not needing to copy the incoming event in the first place. What do you think? RJK PS: Here is what Pbind:embedInStream would look like (changes in bold and italicized) embedInStream { arg inevent; var event = EvaluationEvent.new; var sawNil = false; var streampairs = patternpairs.copy; var endval = streampairs.size - 1; forBy (1, endval, 2) { arg i; streampairs.put(i, streampairs[i].asStream); }; loop { if (inevent.isNil) { ^nil.yield }; event.clear.parent_(inevent); forBy (0, endval, 2) { arg i; var name = streampairs[i]; var stream = streampairs[i+1]; var streamout = stream.next(event); if (streamout.isNil) { ^inevent }; if (name.isSequenceableCollection) { if (name.size > streamout.size) { ("the pattern is not providing enough values to assign to the key set:" + name).warn; ^inevent }; name.do { arg key, i; event.put(key, streamout[i]); }; }{ event.put(name, streamout); }; }; inevent = inevent.putAll(event).yield; } } }
Open this post in threaded view
|

Re: Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 On December 4, 2017 6:34:46 AM "Kuivila, Ronald" <[hidden email]> wrote: > HI James and Julian, > > OK, here is a completely different approach to this. > > The fundamental problem here is that some objects being embedded in a Stream (SimpleNumber and Rest) need to know when that > Stream is an event stream. Right now, Event streams and value streams both get passed an Event as the argument to next. > Instead, value streams could be passed  an instance of a derived class > EvaluationEvent : Event {} > > Then, when Rest::next gets an Event, it would know to write itself into that Event's \dur key and return the Event, since it would get an EvaluationEvent > if it were being used as a value pattern.  So that would loook like: > Rest::next { | ev | (if(ev.class == Event) {^ev.put(\dur, this).yield } { ^this.yield } } Rest:embedInStream, right? I'm going to need some time to think this over. It seems reasonable, but this is not a common usage. It's some effort, and an as yet unknown amount of risk, for something that affects not many people. I think if it were a common case, I'd remember mailing list questions, but I don't. Probably there are more important things to work on. hjh
Open this post in threaded view
|

Re: Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 I'm going to need some time to think this over. It seems reasonable, but this is not a common usage. It's some effort, and an as yet unknown amount of risk, for something that affects not many people. I think if it were a common case, I'd remember mailing list questions, but I don't. Probably there are more important things to work on. Hi James, This is all arising from the desire to use 1 and Rest(1) in EventStream definitions, which is a brand new usage. That usage is convenient but encourages confusion about the distinction between value streams and event streams.  It is currently broken and the fix we have identified will involve changing every pattern that streams sub-patterns. So, if there are more important things to work on, we should delete the asEvent logic altogether.   I would be fine with that. We could add Erest as a syntactic convenience and move on. But, if you are really committed to adding this capability, giving streams the ability to recognize when they are being called by an event stream is probably the way to go.  It will touch the least and keep the value/event polyvalence confined to the classes that implement it. Cheers, RJK hjh
Open this post in threaded view
|

Re: Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 Hi again, Hi James and Julian, OK, here is a simpler way to signal to Rest it is in a value stream: Pbind et. al. set a flag in the Event before updating their substreams and reset that flag before yielding the updated Event So we would have: +Object { isValueStreamEvent { ^true } } +Event { var <>isValueStreamEvent = false; } Then the loop in Pbind would be: loop { if (inevent.isNil) { ^nil.yield }; event = inevent.copy; event.isValueStreamEvent = true; forBy (0, endval, 2) { arg i; var name = streampairs[i]; var stream = streampairs[i+1]; var streamout = stream.next(event); if (streamout.isNil) { ^inevent }; if (name.isSequenceableCollection) { if (name.size > streamout.size) { ("the pattern is not providing enough values to assign to the key set:" + name).warn; ^inevent }; name.do { arg key, i; event.put(key, streamout[i]); }; }{ event.put(name, streamout); }; }; event.isValueStreamEvent = false; inevent = event.yield; } And Rest:embedInStream +Rest { embedInStream { |ev| if (ev.isValueStreamEvent.not}) { ev = ev.put(\dur, this).yield } } But I don't think we would want to add this overhead to SimpleNumber.... RJK On Dec 4, 2017, at 9:54 AM, Kuivila, Ronald <[hidden email]> wrote: I'm going to need some time to think this over. It seems reasonable, but this is not a common usage. It's some effort, and an as yet unknown amount of risk, for something that affects not many people. I think if it were a common case, I'd remember mailing list questions, but I don't. Probably there are more important things to work on. Hi James, This is all arising from the desire to use 1 and Rest(1) in EventStream definitions, which is a brand new usage. That usage is convenient but encourages confusion about the distinction between value streams and event streams.  It is currently broken and the fix we have identified will involve changing every pattern that streams sub-patterns. So, if there are more important things to work on, we should delete the asEvent logic altogether.   I would be fine with that. We could add Erest as a syntactic convenience and move on. But, if you are really committed to adding this capability, giving streams the ability to recognize when they are being called by an event stream is probably the way to go.  It will touch the least and keep the value/event polyvalence confined to the classes that implement it. Cheers, RJK hjh Sent with AquaMail for Android http://www.aqua-mail.com
Open this post in threaded view
|

Re: Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 ---- On Tue, 05 Dec 2017 01:54:16 +0800 Kuivila, Ronald <[hidden email]> wrote ---- >   OK, here is a simpler way to signal to Rest it is in a value stream: I would suggest opening this as an issue with a "future" tag. Bug: Embedding Rest in an event-yielding Pseq can play. Wrapping the same event-yielding Pseq in a filter pattern like Pset can't handle the Rest object. I was trying to hint earlier that this is really not a good time for me to dig deep into this issue. I'm busy. If it's an e-mail thread, then it needs attention *right now*, or it will get lost. There's a kind of extra urgency to it, somehow. If it's a github issue, then there's some accountability to come back to it later. >  Pbind et. al. set a flag in the Event before updating their substreams and reset that flag before yielding the updated Event > >   So we would have: > +Object { isValueStreamEvent { ^true } } > +Event { var <>isValueStreamEvent = false; } > >     Then the loop in Pbind would be: >   >   loop { >  if (inevent.isNil) { ^nil.yield }; >  event = inevent.copy; > event.isValueStreamEvent = true; Probably better to save the current value of isValueStreamEvent before clobbering it with true, and then restore the old value at the end (the same way that Function:prTry restores the previous exception handler, instead of clearing it). I actually have a legitimate use case for nested Pbinds (below). If you assume that isValueStreamEvent will always be false when re-entering the Pbind evaluation cycle, then you break nested Pbinds. >   And Rest:embedInStream +Rest {  embedInStream { |ev| if (ev.isValueStreamEvent.not}) { ev = ev.put(\dur, this).yield } >  } Anyway, currently, you can do Pseq([Rest(1)]).asStream.next (no input event) and get Rest(1). With the above, you'll get an error. So I guess it could be         embedInStream { |inEvent|                 if(inEvent.tryPerform(\isValueStreamEvent) ? true) {                         ^this.yield                 } {                         ^inEvent.put(\dur, this).yield                 }         } >   But I don't think we would want to add this overhead to SimpleNumber.... So, we would fix it only for Rest, but not numbers. I guess I would favor a solution that handles both transparently, without slowing down number-streaming. Needs more thought, which I can't do at the moment. Coming back to nested Pbinds: I haven't used them in a while, but I have some event prototypes that modularize control signals by allocating bus numbers when the event is played, using those bus numbers for a control-event within the main event, and then automatically freeing the bus(es) once all the synths have n_ended. It's structured roughly like: (         instrument: \mySynth,         freq: 440, dur: ... blah blah ...,         ctlEv: (                 instrument: \ctlEnv,                 env: Env(.....),                 out: { ~buslock }         ) ) ... where ~buslock is the newly-allocated Bus. I had been generating these events by Pbind(... blah blah..., \ctlEv, Pbind(...)). If we finally decide to use a flag (about which I have some doubts), then the flag needs to handle recursive usage, or this case breaks. Also, this is a counterexample to the idea of removing inevent.copy. If Pbind does not copy the incoming event, then ctlEv will be identical to its parent: an infinitely recursive data structure. To prevent this, I would have to add a PcopyInval filter pattern or some such and change my user code: Pbind(... blah blah..., \ctlEv, PcopyInval(Pbind(...))). I realize currently this is more like daydreaming about code (Glengarry Glen Ross: "We're not TALKING about it, we're just talking about it"). Still, think carefully and move slowly. Doing this wrong has the potential to break a lot. hjh _______________________________________________ sc-dev mailing list info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspxarchive: http://www.listarc.bham.ac.uk/marchives/sc-dev/search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/
Open this post in threaded view
|

Re: Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 ---- On Tue, 05 Dec 2017 09:20:41 +0800 <[hidden email]> wrote ---- > >   And Rest:embedInStream +Rest {  embedInStream { |ev| if (ev.isValueStreamEvent.not}) { ev = ev.put(\dur, this).yield } > >  } >   > Anyway, currently... PS "Anyway" reads a little funny here... I had deleted an irrelevant sentence about formatting and didn't delete the "anyway" following it... no big deal but on review, it does look weird ;) hjh _______________________________________________ sc-dev mailing list info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspxarchive: http://www.listarc.bham.ac.uk/marchives/sc-dev/search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/
Open this post in threaded view
|

Re: Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 In reply to this post by jamshark70-2 > On 05.12.2017, at 02:20, [hidden email] wrote: > > I realize currently this is more like daydreaming about code (Glengarry Glen Ross: "We're not TALKING about it, we're just talking about it"). Still, think carefully and move slowly. Doing this wrong has the potential to break a lot. Currently, I would consider using Rests and numbers *in place of* events to be a non-supported half-feature. That is, do not do this at home. I’m surprised it ever worked, but this might be my ignorance! Nevertheless, in all this, there is a great potential for a pattern system refactoring. There are other topics, such as making patterns value filters, and reconstructing the cleanup system, which seem very promising. Let’s aim for making the system simpler and more general at the same time. If some feature makes it a lot more complicated, let’s not implement it, because that will make it harder to maintain and extend. signature.asc (849 bytes) Download Attachment
Open this post in threaded view
|

Re: Handling Rest in event streams Re: [sc-dev] What to do about asEvent?

 Hi guys, Sure, a delay of game is a good idea. Can we remove the class extensions at the end of Rest.sc for the release of official release of 3.9?  That would put the genie back in the bottle while we work this out. If so, this paragraph in the help file: A Rest may be used in event patterns to indicate that the resulting event should be a rest (i.e., silent). It should be used in one of the child patterns belonging to a Pbind, for instance. // do nothing for 2 seconds (note:Rest(), dur:2).play; // intersperse pauses in pattern Pbind(\note, Pseq([0, 4, 7, 11], inf), \dur, Pseq([2, 1, Rest(1)], inf) / 5).play; Could be altered and expanded to this: A Rest may be used in the definition of an event pattern (using Pbind, Pbindf and Pmono) to indicate that the resulting event should be a rest (i.e., silent).   For example: // do nothing for 2 seconds (note:Rest(), dur:2).play; // intersperse pauses in pattern Pbind(\note, Pseq([0, 4, 7, 11], inf), \dur, Pseq([2, 1, Rest(1)], inf) / 5).play; For patterns that sequence event patterns, Event.rest can be used to insert rests For example: p = Pbind(\degree, Pbrown(-7, 7,2,4), \dur, 0.2); Pseq([p, Event.silent(1), p, Event.silent(2)], 4).play Cheers, RJK PS: This is what would be deleted or commented out from Rest.sc + SimpleNumber { // Some patterns call .delta on the eventstream's yield value // since a SimpleNumber is a valid rest, it must answer 'delta' with itself delta {} // but Ppar and several other patterns do "put(\delta, ...)" // so they need to convert the simplenumber into a real rest event asEvent { ^Event.silent(this) } } + Event { asEvent {} } + Nil { // Ppar etc. need stream.next(event).asEvent to be nil when the stream ends asEvent {} } note:  On Dec 5, 2017, at 4:22 AM, [hidden email] wrote: On 05.12.2017, at 02:20, [hidden email] wrote: I realize currently this is more like daydreaming about code (Glengarry Glen Ross: "We're not TALKING about it, we're just talking about it"). Still, think carefully and move slowly. Doing this wrong has the potential to break a lot. Currently, I would consider using Rests and numbers *in place of* events to be a non-supported half-feature. That is, do not do this at home. I’m surprised it ever worked, but this might be my ignorance! Nevertheless, in all this, there is a great potential for a pattern system refactoring. There are other topics, such as making patterns value filters, and reconstructing the cleanup system, which seem very promising. Let’s aim for making the system simpler and more general at the same time. If some feature makes it a lot more complicated, let’s not implement it, because that will make it harder to maintain and extend.