SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/ Stream.sc

View: New views
13 Messages — Rating Filter:   Alert me  

SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/ Stream.sc

by jamshark70 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Revision: 9062
          http://supercollider.svn.sourceforge.net/supercollider/?rev=9062&view=rev
Author:   jamshark70
Date:     2009-04-17 12:39:21 +0000 (Fri, 17 Apr 2009)

Log Message:
-----------
2 fixes:

- compose*Op methods for Stream needed to .asStream the other operand(s)

- Per discussion with Ron @ symposium, schedule a Routine in EventStreamPlayer to assist with server sync - Ron will do a 'sync' event type

Modified Paths:
--------------
    trunk/build/SCClassLibrary/Common/Streams/Stream.sc

Modified: trunk/build/SCClassLibrary/Common/Streams/Stream.sc
===================================================================
--- trunk/build/SCClassLibrary/Common/Streams/Stream.sc 2009-04-17 12:27:41 UTC (rev 9061)
+++ trunk/build/SCClassLibrary/Common/Streams/Stream.sc 2009-04-17 12:39:21 UTC (rev 9062)
@@ -168,26 +168,26 @@
  }
  composeBinaryOp { arg argSelector, argStream, adverb;
  if(adverb.isNil) {
- ^BinaryOpStream.new(argSelector, this, argStream)
+ ^BinaryOpStream.new(argSelector, this, argStream.asStream)
  } {
  if (adverb == 'x') {
- ^BinaryOpXStream.new(argSelector, this, argStream);
+ ^BinaryOpXStream.new(argSelector, this, argStream.asStream);
  };
  };
  ^nil
  }
  reverseComposeBinaryOp { arg argSelector, argStream, adverb;
  if(adverb.isNil) {
- ^BinaryOpStream.new(argSelector, argStream, this)
+ ^BinaryOpStream.new(argSelector, argStream.asStream, this)
  } {
  if (adverb == 'x') {
- ^BinaryOpXStream.new(argSelector, argStream, this);
+ ^BinaryOpXStream.new(argSelector, argStream.asStream, this);
  };
  };
  ^nil
  }
  composeNAryOp { arg argSelector, anArgList;
- ^NAryOpStream.new(argSelector, this, anArgList);
+ ^NAryOpStream.new(argSelector, this, anArgList.collect(_.asStream));
  }
 
  embedInStream { arg inval;
@@ -483,7 +483,8 @@
 
  clock.play({
  if(isWaiting and: { nextBeat.isNil }) {
- clock.sched(0, this);
+ // this bit of indirection allows server sync within patterns
+ clock.sched(0, (Routine { |time| loop { time = this.next(time).yield } }));
  isWaiting = false;
  this.changed(\playing)
  };


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

_______________________________________________
sc-dev mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/

pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

An example for the 'sync' fix:

p = Pfset({
b = ~bufnum = Buffer.readAndQuery(s, "sounds/a11wlk01.wav");
(delta: 0, play: { s.sync }).yield;
"synced".debug;
}, Pbind(
\instrument, \bufGrainPan,
\start, Pwhite(0, 100000, inf),
\time, 0.2,
\pan, Pwhite(-1.0, 1.0, inf)
), { ~bufnum.free; "freed buffer".debug }).play;

Ron - did you have anything in mind for the sync event type fancier than this? (I didn't commit this yet.)

sync: #{ |server|
server.sync(~condition)
},

Should we assume delta = 0 when syncing?
hjh


On Apr 17, 2009, at 8:39 AM, jamshark70@... wrote:

Revision: 9062
Author:   jamshark70
Date:     2009-04-17 12:39:21 +0000 (Fri, 17 Apr 2009)

Log Message:
-----------
2 fixes:

- compose*Op methods for Stream needed to .asStream the other operand(s)

- Per discussion with Ron @ symposium, schedule a Routine in EventStreamPlayer to assist with server sync - Ron will do a 'sync' event type


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman


Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by ronald kuivila :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

 No, it should the basic event would just sync and return a delta of 0.
It would be possible to have a syncNoTimingCompression that delays the whole pattern by the
time delay of the sync message. I will get to this stuff at the end of the day.

RJK


On Apr 17, 2009, at 8:50 AM, James Harkins wrote:

An example for the 'sync' fix:

p = Pfset({
b = ~bufnum = Buffer.readAndQuery(s, "sounds/a11wlk01.wav");
(delta: 0, play: { s.sync }).yield;
"synced".debug;
}, Pbind(
\instrument, \bufGrainPan,
\start, Pwhite(0, 100000, inf),
\time, 0.2,
\pan, Pwhite(-1.0, 1.0, inf)
), { ~bufnum.free; "freed buffer".debug }).play;

Ron - did you have anything in mind for the sync event type fancier than this? (I didn't commit this yet.)

sync: #{ |server|
server.sync(~condition)
},

Should we assume delta = 0 when syncing?
hjh


On Apr 17, 2009, at 8:39 AM, jamshark70@... wrote:

Revision: 9062
Author:   jamshark70
Date:     2009-04-17 12:39:21 +0000 (Fri, 17 Apr 2009)

Log Message:
-----------
2 fixes:

- compose*Op methods for Stream needed to .asStream the other operand(s)

- Per discussion with Ron @ symposium, schedule a Routine in EventStreamPlayer to assist with server sync - Ron will do a 'sync' event type


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman



Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Apr 17, 2009 at 9:14 AM, ronald kuivila <rkuivila@...> wrote:
>  No, it should the basic event would just sync and return a delta of 0.
> It would be possible to have a syncNoTimingCompression that delays the whole
> pattern by the
> time delay of the sync message.

I was just thinking of that during my commute, something like this maybe?

sync: { |server|
        var nextTime = currentEnvironment.delta + thisThread.beats;
        server.sync(~condition, ~bundles, ~latency);
        ~delta = max(0, nextTime - thisThread.beats);
}

(I haven't tested this.)
hjh


--
James Harkins /// dewdrop world
jamshark70@...
http://www.dewdrop-world.net

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman

_______________________________________________
sc-dev mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/

Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by ronald kuivila :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

   It might be enough to have:

sync: {
        server.sync(~condition, ~bundles, ~latency);
        ~delta = currentEnvironment.delta + thisThread.beats;
}

IF you do not want the sync based delay to compress the timing of any  
events, you ignore the delay altogether.

RJK
On Apr 17, 2009, at 10:33 AM, James Harkins wrote:

> On Fri, Apr 17, 2009 at 9:14 AM, ronald kuivila  
> <rkuivila@...> wrote:
>>  No, it should the basic event would just sync and return a delta  
>> of 0.
>> It would be possible to have a syncNoTimingCompression that delays  
>> the whole
>> pattern by the
>> time delay of the sync message.
>
> I was just thinking of that during my commute, something like this  
> maybe?
>
> sync: { |server|
> var nextTime = currentEnvironment.delta + thisThread.beats;
> server.sync(~condition, ~bundles, ~latency);
> ~delta = max(0, nextTime - thisThread.beats);
> }
>
> (I haven't tested this.)
> hjh
>
>
> --
> James Harkins /// dewdrop world
> jamshark70@...
> http://www.dewdrop-world.net
>
> "Come said the Muse,
> Sing me a song no poet has yet chanted,
> Sing me the universal."  -- Whitman
>
> _______________________________________________
> sc-dev mailing list
>
> info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
> archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
> search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/
>


_______________________________________________
sc-dev mailing list

info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/

Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Apr 18, 2009, at 6:46 AM, ronald kuivila wrote:

sync: {
server.sync(~condition, ~bundles, ~latency);
~delta = currentEnvironment.delta + thisThread.beats;
}

No, because thisThread.beats after the sync is not the same as thisThread.beats before.

To me, the most intuitive semantics are, the next event occurs delta beats after the logical time when the event was yielded. To do that, we have to save the logical time in a variable before syncing.

hjh


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman


Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by ronald kuivila :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

That is the point!  This was for the syncWithoutTimingCompression alternative.

RJK

On Apr 19, 2009, at 11:20 AM, James Harkins wrote:

On Apr 18, 2009, at 6:46 AM, ronald kuivila wrote:

sync: {
server.sync(~condition, ~bundles, ~latency);
~delta = currentEnvironment.delta + thisThread.beats;
}

No, because thisThread.beats after the sync is not the same as thisThread.beats before.

To me, the most intuitive semantics are, the next event occurs delta beats after the logical time when the event was yielded. To do that, we have to save the logical time in a variable before syncing.

hjh


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman



Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Ron wrote:

Hi James,

  'sync no timing compression' means that any time lost in the sync message is ignored - all events are delayed by that amount.
So the timing of the EventStream will drift wrt to realtime.  (Generally the delta associated with a synch would be 0, so it is more or less
guaranteed to drift.) The question is if the EventStream and the clock that schedules it remain in sync.
If they do, the problem you were describing will be avoided.

  During the time waiting for the sync from the server, other clients of the clock may run.  I don't think this is
a major problem (basically whatever they do during that interval will be stretched by the delay created by the sync).
It might be.  If so, you would have to suspend the clock for the sync time.  You could probably do that by grabbing its queue
and setting it to an empty array.

  Anyway, this is all a bit speculative.  The good example would be loading a few hundred megabytes of soundfile into buffers.


RJK

This is also (still) hijacking the thread. I'm reposting the message into the proper thread.
hjh


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman


Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Another problem with this, and I think this is a deal breaker.

Because the proposed change (well, actually the change is already checked in but it would be easy to revert) places a Routine on the clock instead of the EventStreamPlayer, it means that cmd-. calls removedFromScheduler on the routine instead of the player, so that the player's cleanup actions will not execute.

In my view, that means the workaround Ron and I investigated for pattern sync is a bad approach. In fact, I think it's such a bad side effect I'm going to revert the change now.

We can come back to the issue after 3.3. Being able to sync within patterns is, to me, nice to have but not critical. Since the complications are multiplying (everywhere I look, there's another one), better to get rid of it now.

hjh

On Apr 20, 2009, at 8:44 AM, James Harkins wrote:

Ron wrote:

Hi James,

  'sync no timing compression' means that any time lost in the sync message is ignored - all events are delayed by that amount.
So the timing of the EventStream will drift wrt to realtime.  (Generally the delta associated with a synch would be 0, so it is more or less
guaranteed to drift.) The question is if the EventStream and the clock that schedules it remain in sync.
If they do, the problem you were describing will be avoided.

  During the time waiting for the sync from the server, other clients of the clock may run.  I don't think this is
a major problem (basically whatever they do during that interval will be stretched by the delay created by the sync).
It might be.  If so, you would have to suspend the clock for the sync time.  You could probably do that by grabbing its queue
and setting it to an empty array.

  Anyway, this is all a bit speculative.  The good example would be loading a few hundred megabytes of soundfile into buffers.


RJK


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman


Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by ronald kuivila :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

Well, try the following, which I sent you off-list and you may not have noticed.
The basic idea is to more or less enclose the Routine within the object.  This should solve
the CmdPeriod issue.

RJK

EventStreamPlayer : PauseStream {
var <>event, <>muteCount = 0, <>cleanup, <>routine;

*new { arg stream, event;
^super.new(stream)
.event_(event ? Event.default)
.cleanup_(EventStreamCleanup.new)
.routine_(Routine| inTime | loop { inTime = this.prNext(inTime).yield } });
}

// freeNodes is passed as false from
//TempoClock:cmdPeriod
removedFromScheduler { | freeNodes = true |
nextBeat = nil;
cleanup.terminate(freeNodes);
this.prStop;
this.changed(\stopped);
}
prStop {
stream = nextBeat = nil;
isWaiting = false;
 }

stop {
cleanup.terminate;
this.prStop;
this.changed(\userStopped);
}

mute { muteCount = muteCount + 1; }
unmute { muteCount = muteCount - 1; }
canPause { ^this.streamHasEnded.not and: { cleanup.functions.isEmpty } }

next { | inTime | ^routine.next(inTime) }

prNext { arg inTime;
var nextTime;
var outEvent = stream.next(event.copy);
if (outEvent.isNil) {
streamHasEnded = stream.notNil;
cleanup.clear;
this.removedFromScheduler;
^nil
}{
nextTime = outEvent.playAndDelta(cleanup, muteCount > 0);
if (nextTime.isNil) { this.removedFromScheduler; ^nil };
nextBeat = inTime + nextTime; // inval is current logical beat
^nextTime
};
}

asEventStreamPlayer { ^this }

play { arg argClock, doReset = (false), quant;
if (stream.notNil, { "already playing".postln; ^this });
if (doReset, { this.reset });
clock = argClock ? clock ? TempoClock.default;
streamHasEnded = false;
stream = originalStream;
isWaiting = true; // make sure that accidental play/stop/play sequences
// don't cause memory leaks
era = CmdPeriod.era;
quant = quant.asQuant;
event = event.synchWithQuant(quant);

clock.play({
if(isWaiting and: { nextBeat.isNil }) {
clock.sched(0, 
Routine| inTime | loop { inTime = this.next(inTime).yield } }
);
isWaiting = false;
this.changed(\playing)
};
nil
}, quant);
this.changed(\userPlayed);
^this
}

}

On Apr 20, 2009, at 10:12 PM, James Harkins wrote:

Another problem with this, and I think this is a deal breaker.

Because the proposed change (well, actually the change is already checked in but it would be easy to revert) places a Routine on the clock instead of the EventStreamPlayer, it means that cmd-. calls removedFromScheduler on the routine instead of the player, so that the player's cleanup actions will not execute.

In my view, that means the workaround Ron and I investigated for pattern sync is a bad approach. In fact, I think it's such a bad side effect I'm going to revert the change now.

We can come back to the issue after 3.3. Being able to sync within patterns is, to me, nice to have but not critical. Since the complications are multiplying (everywhere I look, there's another one), better to get rid of it now.

hjh

On Apr 20, 2009, at 8:44 AM, James Harkins wrote:

Ron wrote:

Hi James,

  'sync no timing compression' means that any time lost in the sync message is ignored - all events are delayed by that amount.
So the timing of the EventStream will drift wrt to realtime.  (Generally the delta associated with a synch would be 0, so it is more or less
guaranteed to drift.) The question is if the EventStream and the clock that schedules it remain in sync.
If they do, the problem you were describing will be avoided.

  During the time waiting for the sync from the server, other clients of the clock may run.  I don't think this is
a major problem (basically whatever they do during that interval will be stretched by the delay created by the sync).
It might be.  If so, you would have to suspend the clock for the sync time.  You could probably do that by grabbing its queue
and setting it to an empty array.

  Anyway, this is all a bit speculative.  The good example would be loading a few hundred megabytes of soundfile into buffers.


RJK


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman



Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by ronald kuivila :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

Here is a tested version.  I am going to go ahead and commit this in the interest of further testing.

RJK

EventStreamPlayer : PauseStream {
var <>event, <>muteCount = 0, <>cleanup, <>routine;


*new { arg stream, event;
^super.new(stream).event_(event ? Event.default).init;
}

init {
var me = this;
cleanup = EventStreamCleanup.new;
routine = Routine{ | inTime | loop { inTime = me.prNext(inTime).yield } };
}


// freeNodes is passed as false from
//TempoClock:cmdPeriod
removedFromScheduler { | freeNodes = true |
nextBeat = nil;
cleanup.terminate(freeNodes);
this.prStop;
this.changed(\stopped);
}
prStop {
stream = nextBeat = nil;
isWaiting = false;
 }


stop {
cleanup.terminate;
this.prStop;
this.changed(\userStopped);
}


mute { muteCount = muteCount + 1; }
unmute { muteCount = muteCount - 1; }
canPause { ^this.streamHasEnded.not and: { cleanup.functions.isEmpty } }


next { | inTime | ^routine.next(inTime) }


prNext { arg inTime;
var nextTime;
var outEvent = stream.next(event.copy);
if (outEvent.isNil) {
streamHasEnded = stream.notNil;
cleanup.clear;
this.removedFromScheduler;
^nil
}{
nextTime = outEvent.playAndDelta(cleanup, muteCount > 0);
if (nextTime.isNil) { this.removedFromScheduler; ^nil };
nextBeat = inTime + nextTime; // inval is current logical beat
^nextTime
};
}


asEventStreamPlayer { ^this }


play { arg argClock, doReset = (false), quant;
if (stream.notNil, { "already playing".postln; ^this });
if (doReset, { this.reset });
clock = argClock ? clock ? TempoClock.default;
streamHasEnded = false;
stream = originalStream;
isWaiting = true; // make sure that accidental play/stop/play sequences
// don't cause memory leaks
era = CmdPeriod.era;
quant = quant.asQuant;
event = event.synchWithQuant(quant);

clock.play({
if(isWaiting and: { nextBeat.isNil }) {
clock.sched(0, this );
isWaiting = false;
this.changed(\playing)
};
nil
}, quant);
this.changed(\userPlayed);
^this
}

}


Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

OK, thanks. I did see the other one but didn't think it would work, since it was still scheduling the Routine.

One of my concerns is that I'm going into a period where I need to concentrate on composing. I think we're very close now -- but, I may not have time for rigorous testing. OTOH, composing is where I push the capabilities further than simple test cases :)  but then I can't guess when I would run into a hard situation, can't be sure it would be in time for 3.3.

Anyway, your last change is good (though the 'me' variable is probably superfluous - the init method will remember who 'this' is, right?)

routine = Routine{ | inTime | loop { inTime = this.prNext(inTime).yield } };

hjh


On Apr 21, 2009, at 7:13 AM, ronald kuivila wrote:

Hi James,

Here is a tested version.  I am going to go ahead and commit this in the interest of further testing.


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman


Re: pattern sync fix (was: Re: SF.net SVN: supercollider:[9062] trunk/build/SCClassLibrary/Common/Streams/Stream.sc)

by ronald kuivila :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

Quite right, residual paranoia from doing things in the interpreter...

RJK

On Apr 21, 2009, at 8:05 AM, James Harkins wrote:

OK, thanks. I did see the other one but didn't think it would work, since it was still scheduling the Routine.

One of my concerns is that I'm going into a period where I need to concentrate on composing. I think we're very close now -- but, I may not have time for rigorous testing. OTOH, composing is where I push the capabilities further than simple test cases :)  but then I can't guess when I would run into a hard situation, can't be sure it would be in time for 3.3.

Anyway, your last change is good (though the 'me' variable is probably superfluous - the init method will remember who 'this' is, right?)

routine = Routine{ | inTime | loop { inTime = this.prNext(inTime).yield } };

hjh


On Apr 21, 2009, at 7:13 AM, ronald kuivila wrote:

Hi James,

Here is a tested version.  I am going to go ahead and commit this in the interest of further testing.


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman