SuperCollider Forum
May 18, 2013, 06:16:53 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: The SuperCollider forum is currently experiencing a rash of spambot registrations. New user requests may not be approved quickly as a result -- and if your email address looks like spam, it might not be approved at all. We are working to improve the security of the registration process, and to provide alternate means to contact the administrators to get a new account. Thanks for your patience.
 
   Home   Help Search Calendar Login Register  
Pages: [1]
  Print  
Author Topic: Thinking about structure in a through-composed piece  (Read 6732 times)
0 Members and 1 Guest are viewing this topic.
dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« on: May 20, 2008, 08:32:12 PM »

Whew! Spent most of the weekend debugging some really knotty code, but finally got it working well enough and discovered the constraints to make the code continue to work (which is just as important).

It's all about flow of control for a piece for violin and computer where some (perhaps most) sections will be rhythmic with a lot of meter changes. So here's what I had on my mind --

- the performer should be able to jump ahead and start the computer part at every rehearsal marking;

- the computer needs to know when one section ends (crosses over to the next rehearsal mark) and automatically update;

- sections should load their resources incrementally, which I ended up implementing through forwarding of notifications;

- the "conductor" process, which performs meter changes and provides other high-level information to sound-making processes, has to run ahead of everything else so that its information is ready before other processes use that information;

- that means the "section" object must start just ahead of the beat, in time with the conductor, and other processes have to schedule themselves properly relative to the meter -- this called for "command" objects that describe the action to be performed along with all the parameters that are needed (such as a Quant-style scheduling specification) -- commands also know their status and can notify the caller when they complete;

- one section yields control to another when all of its processes run out of material -- but of course some processes need to run continuously across section boundaries. That's where it gets really confusing, with some process-trigger commands that can synchronize (which will hold the end of the section until they finish) and others that don't have to synchronize -- in which case they get saved at the end of the section and passed on into the next section.

- And of course all of this has to be run by a GUI that a non-technical person could use.

As long as I make sure that only the conductor can synchronize and that every other process either plays through or explicitly stops itself at the right time, I think I can build a fairly long piece this way. It remains to be seen whether the structure will survive past this composition -- if anything, it's too complicated for its own good -- but maybe it just needs some re-factoring later on.

Just trying to start some conversation -- I know this is sketchy on the details. What's interesting to you in any of this?

hjh
Logged

joshp
AdminGroup
Full Member
*

Karma: 5
Posts: 121



View Profile WWW
« Reply #1 on: May 20, 2008, 09:06:57 PM »

Things like this are what I made ProcMod and ProcEvents for. Especially the start anywhere for rehearsals aspect. I look forward to seeing what you finish up with! Looking at these kinds of systems that take care of large-scale compositional needs is fascinating to me, and I think one of the real changes that has occurred with live electronics pieces as the languages we use become more sophisticated. As you and more composers start to consider these large scale considerations, I think the languages will eventually start to develop built in mechanisms for these things (in the same way that almost every language can deal with pitch and rhythm at a basic level... I think there will be a standard of practices that start to take shape to deal with the organizational problems you are dealing with here as well).
Logged
dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« Reply #2 on: May 21, 2008, 08:12:30 PM »

I guess I would have to see that kind of standard as something rather far in the future. It puts me in mind of the recent nextTimeOnGrid discussion on the mailing lists -- disputes arise over even something so basic as how to describe the onset time of a routine or other kind of process. The current "standard" way to do it embodies some of Julian R's rather specific assumptions which I, frankly, disagree with and find to be counterproductive for my purposes, but I can live with it because this is wrapped in an object-oriented layer so it's fairly straightforward to substitute that logic with something I find more sensible.

Standards call for compromises, or at least agreement on the basic requirements and a recognition that people will have to accept some adjustments in their preferred way of working to make it easier to share information. But we're not even really having a conversation about the requirements yet.

On a more optimistic note... at least the system I'm working on now is based on something like the command design pattern as the basic building block. Everything gets activated by a command object that has a standard interface ("play" to make it go and "stop" to terminate it). Commands can also stop themselves, immediately or at some time in the future, and send "changed" notifications so that their parent knows who is active at any time. If you need to do something for which a command doesn't already exist, just add a new subclass and you're done.

That frees me from the responsibility of anticipating every possible action.

I think another challenge is that these large systems end up becoming "dialects" of the base language. Newcomers have a hard enough time dealing with "out-of-the-box" supercollider, but then to take advantage of somebody else's thinking about hard problems, they have to conform to a coding style that looks quite different from anything they've seen in help files. That's true of my work as well as crucial, JITLib, Ctk and I'm sure the list goes on. I'm not sure how to address that, other than publishing more examples.

hjh
Logged

joshp
AdminGroup
Full Member
*

Karma: 5
Posts: 121



View Profile WWW
« Reply #3 on: May 21, 2008, 08:47:11 PM »

Of course (to pretty much all of that). I think we are in a period similar to what was happening in the pre-classical period of western music, where there was an extension of past practices that eventually morphed into something new. As high tech as the tools we use seem, they are really still quite rudimentary! What I think is great about what we are able to do now though is that a number of composers are able to show MANY others, quite quickly. I think there would be a problem of anyone at this point trying to standardize anything (it is too early for compromises), but within the next 10 or so years, I think a common practice will start to develop.
-How do we start things?
-How do we make pieces where we can start and rehearse them at any point?
-What are the basics that every language must have?
Just to mention a few (that are drawn mostly from this conversation already). This is an exciting time to be working in this medium. Many of the basic problems have been solved (how to make a sin tone, FM, FFT techniques, etc.), and it is really time for the artistic concerns to come to the forefront. These tools that you are describing are the new basics that need to be constructed, but MANY people, before a practice will start to emerge. I'm tired of hearing piece after piece that sounds like a loose structuring of Max patches where sounds are turned up and down as needed. As THIS work starts to be done, a practice that is more sophisticated will start to develop, and I think we will start seeing more and more tools that offer a more mature way to deal with the structure of a piece.
Logged
dewdrop_world
AdminGroup
Full Member
*

Karma: 9
Posts: 193



View Profile WWW
« Reply #4 on: May 25, 2008, 01:11:30 PM »

Been busy... I'll come back to Josh's points (good ones) later. In the meantime, I posted some more details at electro-music.com and thought I should share them here also.

Attachments bigger than 256K are not permitted here, so follow the electro-music link to hear the excerpt.

hjh

---

Here's a short excerpt. The breakbeat is chugging along, along with kick drum and snare accents. Today I also added a prototype of a bassline -- I'm not quite happy with it but I wanted to be sure I could generate the material and have the harmonic content change at the right times in the score.

Forgive the rough mix -- this is at a really early stage of production.

And, the code as it stands now (excluding the process details, since this thread is about the higher-level structure) -- it uses other code that exists locally on my machine, which I'm not ready to release yet (sorry). But at least it might make it more concrete what I mean by "sections" and "commands."

James

Code:
// must load proto-cmds, core processes and transports, before doing this
(
BP.all.free;

~sections = [PR(\tlSection).copy.putAll((
startBeatsPerBar: 4,
initProcesses: {
BP(\cond).free;
PR(\conductor).chuck(BP(\cond), nil, (
meter: Pseq([4, 3, 15/4, 4, 3], 1),
numBars: Pseq(#[1, 1, 1, 3, 1], 1),
barDiv: Pseq([
(bass: #[0, 0.75], snr: #[1.5], avail: (8..15)),
(bass: #[0, 1.5], snr: #[0.75, 2.25], avail: \getRests),
(bass: #[0, 1.25, 2.5], snr: #[0.75, 2, 3.25], avail: \getRests),
(bass: #[0, 0.5, 1.5], snr: #[1, 2, 2.5], avail: (12..15)),
(bass: #[0, 3.25], snr: #[3, 3.75], avail: (0..15)),
(bass: #[0], snr: #[0.5], avail: (4..15)),
(bass: #[1.5, 2.0, 2.25, 2.75], snr: #[2.5], avail: (0..5))
], 1)
));

// more processes get initialized here (omitted)

},
seqPattern: {
Pbind(
\sequence, Pseq([
[funcCmd: (func: {
BP(#[brk, k, snr, b2]).do(_.cond_(\cond))
}),
funcCmd: (func: { Library.put(\bassMapping, #[31, 37, 39, 43, 45].mapMode(\gmin)) }),
bpCmd: (name: #[brk, k , snr, b2], quant: #[1, 0], shouldSync: false),
bpCmd: (name: #[cond], quant: #[1, 0]),
23.75, notifyCmd: (notification: \initNext, passthru: true)]
], 1),
\dur, \sync
)
},
name: "break"
)),
PR(\tlSection).copy.putAll((
name: "break2",
initProcesses: {
PR(\conductor).chuck(BP(\cond2), nil, (
meter: Pseq([4, 3, 1.25, 5, 1.25, 3, 1.25, 4, 2, 4, 3, 4, 3, 1.5, 3], 1),
numBars: Pseq(#[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 2], 1),
barDiv: Pseq([
(bass: #[0, 2.5], snr: #[1, 3], avail: \getRests),
(bass: #[0, 2.5], snr: #[1], avail: \getRests),
(snr: #[0], avail: \getRests),
(bass: #[0, 2.5, 4], snr: #[1, 3], avail: \getRests),
(snr: #[0], avail: \getRests),
(bass: #[0, 2.5], snr: #[1], avail: \getRests),
(snr: #[0], avail: \getRests),
(bass: #[0, 2.5], snr: #[1, 3.5], avail: \getRests),
(bass: #[0], snr: #[0.5, 1.5], avail: \getRests),
(bass: #[0], avail: (2..15)),
(snr: #[1, 1.75, 2.25], avail: #[0, 1, 2, 3, 10, 11]),
(bass: #[0, 0.75], snr: #[1.5], avail: (8..11)),
(bass: #[0, 2.5], snr: #[0.75, 1.5, 3, 3.25], avail: \getRests),
(bass: #[1, 2.75], snr: #[0, 0.5, 1.25, 2, 2.25, 3], avail: \getRests),
(bass: #[0, 0.75, 1.5, 3], snr: #[1, 2.5, 3.25], avail: \getRests),
(snr: #[0, 0.75, 1.5, 2.25], avail: \getRests),
(snr: #[0, 0.75, 1.5, 2.25], avail: \getRests),
(snr: #[0, 0.75], avail: \getRests)
], 1)
));
BP(\cond2).leadTime = 0.2;
},
seqPattern: {
Pbind(
\sequence, Pseq([
[funcCmd: (func: {
BP(#[brk, k , snr, b2]).do({ |bp| bp.cond_(\cond2) });
}),
// change pitch content of bass at start of section
funcCmd: (func: { Library.put(\bassMapping, #[31, 38, 41].mapMode(\gmin)) }),
bpCmd: (name: #[brk, k , snr, b2], quant: #[1, 0], shouldSync: true),
bpCmd: (name: #[cond2], quant: #[1, 0], stopAll: true),
4+3+5+3+4+2+(3*1.25),
// change content again
funcCmd: (func: { Library.put(\bassMapping, #[31, 37, 43, 45].mapMode(\gmin)) }),
22,
funcCmd: (func: { Library.put(\bassMapping, #[38, 43, 45, 48].mapMode(\gmin)) })
]
], 1),
\dur, \sync
)
}
))
];
)

~seq = PR(\sectionSequencer).copy.putAll((
sections: ~sections
));

PR(\transports).copy.model_(~seq) => BP(\transports);
Logged

Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC Valid XHTML 1.0! Valid CSS!