electro-music.com   Dedicated to experimental electro-acoustic
and electronic music
 
    Front Page  |  Radio
 |  Media  |  Forum  |  Wiki  |  Links
Forum with support of Syndicator RSS
 FAQFAQ   CalendarCalendar   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   LinksLinks
 RegisterRegister   ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in  Chat RoomChat Room 
 Forum index » DIY Hardware and Software » ChucK programming language
Instantiating a shred reference without sporking a shred...
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [17 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
Author Message
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Tue Dec 18, 2007 8:37 am    Post subject: Instantiating a shred reference without sporking a shred... Reply with quote  Mark this post and the followings unread

Is this possible?

A simple example would be the following....

Code:


int Choose;
int ID;

Std.rand2(1,2) => Choose;

if (Choose == 1)
{
   spork ~ foo1() @=> Shred @ f1;
}
if (Choose == 2)
{
   spork ~ foo2() @=> Shred @ f2;
}

// define function
fun void foo1()
{
   1 => ID;    
       while( true )
       {
              <<< "shred1" >>>;
           .2::second => now;
       }
}

fun void foo2()
{
   2 => ID;   
       while( true )
       {
              <<< "shred2" >>>;
           .2::second => now;
       }
}
2::second => now;

if (ID == 1)
{
   Machine.remove( f1.id() );
}
if (ID == 2)
{
   Machine.remove( f2.id() );
}
<<<"Removing", Choose>>>;
2::second => now;



However, this wont work because it tells me there is an undefined variable f1. The problem is that the only way I know of that it can be defined is by using the following line...

Code:


spork ~ foo1() @=> Shred @ f1;



....but that means that the shred runs when I dont want it too?! Sad

How can I avoid this error with having to first spork the shred?

Thanks,

Rhys
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Tue Dec 18, 2007 10:31 am    Post subject: Reply with quote  Mark this post and the followings unread

If I understand the question correctly;

Code:
Shred stein; //make a empty shred reference

spork ~ spank() @=> stein; //assign a shred to it

4::second => now;

stein.exit();

second => now;

<<<"ouch!">>>;


fun void spank()
 {
 while(1)
  {
  <<<"clap">>>;
  .5::second => now; //edit; I missed a period here, now corrected
  }
 }


That's the theory, barring typos this should run fine as well, however this is one of the bits of ChucK that's a bit messy right now. At the moment there is a bug (with a fix in CVS) where Shred references that aren't assigned to a actual shred have a random .id(). Ge reportedly fixed that but I'm not sure whether he has yet had the time to look into another (possibly related) issue where under some circumstances the VM may segmentation-fault when using and re-using such containers. Try to see how far you get and if there are issues it might be a good idea to document them, if possible.

At the moment this stuff is mainly syntactic sugar, personally I'd like to see Shred objects used to help facilitate inter-shred communication but it's not at all clear how that would work, there's a discussion on this in the list archives a few weeks back.

_________________
Kassen

Last edited by Kassen on Tue Dec 18, 2007 10:57 am; edited 1 time in total
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Tue Dec 18, 2007 10:42 am    Post subject: Reply with quote  Mark this post and the followings unread

Thank you very much!

I'll let you know if there are any further problems with this but already using and abusing shreds is helping to save loads of precious processing so it definitely seems like the right path to take.

Rhys
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Tue Dec 18, 2007 10:56 am    Post subject: Reply with quote  Mark this post and the followings unread

Cool. To be perfectly clear; using shreds and lots of them is perfectly fine and quite fundamental to advanced ChucKage. It's the Shred class that references them that can be a trouble maker.

You can get the same functionality using variables that hold the id number of certain shreds too, if you do run into trouble.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Tue Dec 18, 2007 11:38 am    Post subject: Reply with quote  Mark this post and the followings unread

Quote:


You can get the same functionality using variables that hold the id number of certain shreds too, if you do run into trouble.



Can you please give me an example, as I have an idea of what you mean but I think it is the wrong one!
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Tue Dec 18, 2007 12:41 pm    Post subject: Reply with quote  Mark this post and the followings unread

Sure, the best example I could give you is also the one I have in the topic on splines a bit down from this one. In fact, I structured it that way in order to get around a rather nasty crash I got when using Shred references.

The basic trick is that me.id() returns the id of whatever shred calls it and Machine.remove( int id) will remove a shred by it's number.

IMHO that structure is less elegant then instances of Shred that reference to a shred but at least until the patch gets here I would say it's safer.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Tue Dec 18, 2007 1:20 pm    Post subject: Reply with quote  Mark this post and the followings unread

Thanks again for the info. I have found some kind of nasty bug that has stopped me from progressing any further (although again it could be just me out my depth).

Code:


0 => int SporkID;
int BufferSelector;
Shred buffer1shred;
Shred buffer2shred;
Shred buffer3shred;
buffers();

fun void buffers()
{
   Std.rand2(1,3) => BufferSelector;   
   if (SporkID == 1)
   {
      buffer1shred.exit();
   }
   if (SporkID == 2)
   {
      buffer2shred.exit();
   }
   if (SporkID == 3)
   {
      buffer3shred.exit();
   }
   if (BufferSelector == 1)
   {
      spork ~ buffer1() @=> buffer1shred;
   }
   if (BufferSelector == 2)
   {
      spork ~ buffer2() @=> buffer2shred;
   }
   if (BufferSelector == 3)
   {
      spork ~ buffer3() @=> buffer3shred;
   }
}

fun void buffer1()
{
   while (true)
   {
      <<<"aaaa">>>;
   }
}

fun void buffer2()
{
   while (true)
   {   
      <<<"aaaa">>>;
   }
}

fun void buffer3()
{
   while (true)
   {
      <<<"aaaa">>>;
   }
}



For some reason the shreds wont spork?! This has put a large spanner in any well oiled machine I was hoping to build with sporks n shreds.

Hopefully its just something obvious.

Thanks

Rhys
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Tue Dec 18, 2007 1:40 pm    Post subject: Reply with quote  Mark this post and the followings unread

Ok, that's a different matter altogether.

As soon as "buffers" runs it'll start a new shred which is shreduled to run as soon as the original code advances time or yields. With me so far?

Well, right after that the parent shred runs out of stuff to do so it exits. As it exists all of it's children are removed as well so the sporked shred never has a chance to run.

This is easilly fixed by adding "hour => now;" below your call to buffers but beware that the shred it starts in your test setup will have a infinite loop that doesn't advance time and so will clog the VM. Adding something like "ms => now;" to those loops will remedy this and the whole thing will run just fine (I just tested).

I realise that it looks confusing in this setup but this is actually completely proper and logical and all follows from how timing and concurrency work in ChucK. It's therefore often usefull to follow a spork by a me.yield() so the child has a chance to run before anything else happens. I think there is a good explanation on the use of yielding in the manual as well, it's a subtle issue but it does allow you to get very precise about your timing.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Tue Dec 18, 2007 4:04 pm    Post subject: Reply with quote  Mark this post and the followings unread

Excellent. No surprises there then, was brain failure and lack of manual reading on my behalf.

I've got it working again and the processes are much faster now, so much so that I can start work on concurrent threads for bass and more beats without it straining on playback.

Thanks very much.

Rhys
Back to top
View user's profile Send private message
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Tue Dec 18, 2007 4:48 pm    Post subject: Reply with quote  Mark this post and the followings unread

There is this though, which now doesnt make any sense. Obviously it has something to do with the shredding procedure but the time no longer works.

Code:


0 => int SporkID;
int BufferSelector;
Shred buffer1shred;
Shred buffer2shred;
Shred buffer3shred;
buffers();

fun void buffers()
{
   Std.rand2(1,3) => BufferSelector;   
   if (SporkID == 1)
   {
      buffer1shred.exit();
   }
   if (SporkID == 2)
   {
      buffer2shred.exit();
   }
   if (SporkID == 3)
   {
      buffer3shred.exit();
   }
   if (BufferSelector == 1)
   {
      spork ~ buffer1() @=> buffer1shred;
      me.yield();
   }
   if (BufferSelector == 2)
   {
      spork ~ buffer2() @=> buffer2shred;
      me.yield();
   }
   if (BufferSelector == 3)
   {
      spork ~ buffer3() @=> buffer3shred;
      me.yield();
   }
}

fun void buffer1()
{
      <<<"aaaa">>>;
      1::second => now;
      <<<"bbbb">>>;
      1::second => now;
}

fun void buffer2()
{
      <<<"aaaa">>>;
      1::second => now;
      <<<"bbbb">>>;
      1::second => now;
}

fun void buffer3()
{
      <<<"aaaa">>>;
      1::second => now;
      <<<"bbbb">>>;
      1::second => now;
}



Only the first printout works, the second one gets ignored?
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Wed Dec 19, 2007 10:31 am    Post subject: Reply with quote  Mark this post and the followings unread

Yes, that's right.

What happens is that child-shreds get killed if the parent exits. After the "buffers()" call the parent here has nothing more to do so it exits.... so the child exits as well.... so nothing after the child tries to advance time gets executed. Basically the situation as you have it now all plays out in a single moment from ChucK's timing perspective. Put a line along the lines of "hour => now" below the call to "buffers()" and all will be fine.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Wed Dec 19, 2007 12:35 pm    Post subject: Reply with quote  Mark this post and the followings unread

Ok I think I get you.

Am I right in thinking the best way would be to have a parent shred running for a certain length of time then spork child shreds whenever they are needed and kill them off when they are not?

For example...

Code:


Shred buffer1shred;
Shred buffer2shred;

buffers();

fun void buffers()
{
   spork ~ buffer1() @=> buffer1shred;
   2::second => now;
   spork ~ buffer2() @=> buffer2shred;
   2::second => now;
   me.yield();
}

fun void buffer1()
{
   <<<"aaaa">>>;
   1::second => now;
   <<<"bbbb">>>;
   1::second => now;
   //This next line must clean the child shred up right?
   buffer1shred.exit();                                 
}

fun void buffer2()
{
   <<<"cccc">>>;
   1::second => now;
   <<<"dddd">>>;
   1::second => now;
   buffer2shred.exit();
}



If this is the case then how would I then return to the parent shred at the right point in time.

In this case, in order to spork the next child shred when needed but the child shred would have no indication of time passing?

For example:

Code:


int x;
int y;
Shred buffer1shred;
Shred buffer2shred;
buffers();

fun void buffers()
{
   spork ~ buffer1() @=> buffer1shred;
   //Needs to spork buffer2() only when buffer1() shred is finished

        //Will it work in time if there were a huge number of variables
        //and processes such as loading .wavs into buffers?
   spork ~ buffer2() @=> buffer2shred;
   4::second => now;
   me.yield();
}

fun void buffer1()
{
   1 => x;
         5 => y;
        buffer1shred.exit();
}

fun void buffer2()
{
   <<<x>>>;
   <<<y>>>;
   buffer2shred.exit();
}



Once again, apologies for the newbie level of questions, this spork/shred thing is quite tough.

Rhys
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Wed Dec 19, 2007 1:28 pm    Post subject: Reply with quote  Mark this post and the followings unread

Dr. Spankenstein wrote:

Am I right in thinking the best way would be to have a parent shred running for a certain length of time then spork child shreds whenever they are needed and kill them off when they are not?


First of all; everything depends on the parent shred, this is the main shred for every .ck file, it's the one that will have a real name in "chuck --status", it's the one that basically starts running at the top of the file and when it exits everything it started will stop. Child shreds will die, Ugens will stop making sound, etc. Additionally, unless sporked functions redefine variables they share variable names with the parent (at least for those defined before the child got sporked, I never tried what would happen otherwise, maybe that would lead to issues).

Though you are under no obligation to, I think this structure means it's often most convenient and practical to write the main "meat" of your program in that shred.

As for what sporked children do and how; that's really up to you and the design of your program which will depend entirely on what you actually want to do. A algorithmic breakbeat cutter would be structured differently from a utility program to enable you to play both a bassline and a drumkit on two different rack modules from a single MIDI keyboard.

You can spork many child shreds, it's totally possible to spork (hundreds of) thousands of them and at times that may be a sound design choice. Typically though I try to keep it relatively small. For example a shred that makes sounds play in rhythmical patterns and a child shred that takes keyboard input to modify the patterns. With garbage collection being what it is (IE non-existent) I think it's currently unwise to allocate Ugens in child shreds, then kill those shreds off once the note/phrase/whatever has finished playing, it's likely wiser to temporarily disable those Ugens, then use events to wake the shred up again once it can be re-used.

Good design is something that I think comes with experience, there are -of course- many books on program design but so far none on good design for ChucK shreds (likely this will take a while too...). The bad news is that this matters a lot and can make the difference between clogging the CPU and a lean mean music machine, the good news is that experimenting is fun... well, can be.... Ok, I myself like it :¬).

We can take a look at the sort of structure you are after, if you'd like, and see how that could be implemented.

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Wed Dec 19, 2007 2:51 pm    Post subject: Reply with quote  Mark this post and the followings unread

Thank you for making that clear.

Disabling a Ugen would be done using 0 => Ugen.op right?

I think given the way my code is currently structured it would be silly of me to completely overhaul it using sporks. I'll have a look through it and see what parts I can relate to this and then post any ideas/queries I may have.

Thanks for taking the time to talk me through this.

Rhys
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Wed Dec 19, 2007 3:25 pm    Post subject: Reply with quote  Mark this post and the followings unread

Oh, you're welcome, these are tricky and potentially confusing matters and it can't hurt to go over them as I imagine more people then just you read the explanation, we did cover most of the core of ChucK's timing mechanisms in just one page, that's quite good.

As for the benefits of restructuring; a shred waiting for a event doesn't take cpu so using events and a well planned shred structure can save cpu, it can also make sense to split up a large loop with many flow-control flags up into separate shreds to make it more readable.

.op() affects how a Ugen deals with signals, .op(0) indeed stops the processing but I'm not sure how that affects Ugens before it in the chain. I'm sure that unchucking the first of the chain from the dac will stop the whole chain so that's what I use for this.

Either way; now you know so with future projects you can take this stuff into account and write for it. I know that my own projects greatly improved after I got this stuff down (well, knew more about it, I like to think of myself as a n00b too, it makes learning a lot more fun). For low latency realtime projects that need occasional updates good structure means the difference between heaven&hell.

Oh, and I've been thinking about giving workshops in ChucK so thank *you* for letting me abuse you as a guinea pig :¬p

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Dr. Spankenstein



Joined: Mar 03, 2007
Posts: 136
Location: Cambridge
Audio files: 1

PostPosted: Thu Dec 20, 2007 4:36 am    Post subject: Reply with quote  Mark this post and the followings unread

No problem. Smile

Good luck with the ChucK workshops idea!

I think there is a growing need for people like yourself, and workshops such as these, in an age where bedroom producers are on the increase. Not to mention a vast number of computer competent musicians who now demand more flexibility and creativity with their music.

Rhys
Back to top
View user's profile Send private message
Kassen
Janitor
Janitor


Joined: Jul 06, 2004
Posts: 7678
Location: The Hague, NL
G2 patch files: 3

PostPosted: Thu Dec 20, 2007 5:02 am    Post subject: Reply with quote  Mark this post and the followings unread

Ha! A fresh post for me minutes before I log in and without even using the RSS feed, what luck! :¬)

Thanks and yes, I think there is "a hole" there.

The whole bedroom studio generation is interesting ( I'm every bit a part of it). On one hand there is a lot of independence there but on the other the music that comes out if it is also very dependant on the software and hardware that get released and what new features they bring. I know a lot of musicians but I don't think I know a single one that doesn't occasionally complain "X is a great tool bit I just wish it would also.....".

Lots and lots of interesting ideas that people have yet where they don't know where to start realising them. In a way the appearance of software seems every bit as miraculous as the appearance of electronic music in the past, I think, while as you know you *can* get involved yourself and it becomes a lot more fun that way.

So, that's my angle on this :¬).

_________________
Kassen
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic Moderators: Kassen
Page 1 of 1 [17 Posts]
View unread posts
View new posts in the last week
Mark the topic unread :: View previous topic :: View next topic
 Forum index » DIY Hardware and Software » ChucK programming language
Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Forum with support of Syndicator RSS
Powered by phpBB © 2001, 2005 phpBB Group
Copyright © 2003 through 2009 by electro-music.com - Conditions Of Use