Thread: [Pythonsound-devel] Re: Python and music [was Re: New work, new tools] (fwd)
Status: Beta
Brought to you by:
mupuxeddu
|
From: Paul W. <sli...@ya...> - 2001-10-03 20:20:51
|
On Wed, Oct 03, 2001 at 03:52:40PM +0200, Maurizio Umberto Puxeddu wrote: > On Mon, 1 Oct 2001, Paul Winkler wrote: > > I also like the operator overloads I'm using, but that's really just > > sugar. > > > > If you're agreeable to supporting features like .append(), .merge(), > > .extend() and maybe some operator shortcuts for them, I may consider > > dropping pysco entirely and putting my work into OMDE. > > No problem. It can can be done. OK. I will take on the project of going through OMDE and trying to see if / how it can support my ideas. I'd still like to discuss whether objects should be responsible for their own start time, or delegate that to a parent Aggregate. When you get a chance, I'd like to hear your reasoning for making each event responsible for its own start time. The only argument I can see *against* giving this responsibility to the parent (the containing Aggregate) is that it requires you to have a top-level Aggregate to control your composition's overall structure. This might be seen as inconvenient; "I know when this object should start, I want to say so when I create the object." But I think it's actually an advantage to have an explicit top-level Aggregate, because it's easier to see the overall structure of the piece that way. And suppose you want to have two Aggregates which consist of the same events in different order. Let's call the contained events A, B, and C. If each object is responsible for their own start time, that would look something vaguely like this: A = Event(start = 1) B = Event(start = 2) C = Event(start = 3) Agg1 = Aggregate(A, B, C) A2 = copy(A); A2.set_start_time(10) B2 = copy(B); B2.set_start_time(20) C2 = copy(C); C2.set_start_time(0) Agg2 = Aggregate(A2, B2, C2) I have to make copies or else I'll change Agg1 when I only want to change Agg2. On the other hand, if we use the Aggregate to control start time, it's a lot easier. Something like this: A = Event() B = Event() C = Event() Agg1 = Aggregate((1, A), (2, B), (3, C)) Agg2 = Aggregate((10, A), (20, B), (30, C)) As further purely anecdotal evidence, I'll note that the author of Blue does it my way. :) Implementation detail: In pysco, I have been storing the events within an Aggregate (I call them Blobs) as a simple list of [start_time, event] lists. I chose that because it makes it easy to e.g. sort the list by start time. And I use lists rather than tuples so it's easy to replace any event or change any start time. > I need to keep concentrate on my compositions for some time and I'll not > reply very quickly to emails for few days. That's fine - I have plenty of work to do, and I've been working on pysco for almost two years anyway, so you can see I'm in no hurry. :) Anyway, as I found with pysco, trying to compose with it is the best way to improve it - "eat your own dog food" as they say. > I also would like to move this discussion on the pythonsound-devel > list here: > > http://lists.sourceforge.net/lists/listinfo/pythonsound-devel Done. I think there have been some discussions of pmask on the csound list, but not being subscribed anymore, I can't find them - there don't seem to be archives of the csound list anywhere! Are you on the csound list? If so, and if you have time, could you see if there are any interesting pmask-related messages on csound list and forward them to pythonsound-devel? -- ................ paul winkler ................ custom calendars: http://www.calendargalaxy.com A member of ARMS: http://www.reacharms.com home page: http://www.slinkp.com |
|
From: Paul W. <sli...@ya...> - 2001-10-04 15:54:34
|
Maurizio, I know you said you won't have time to deal with design issues this month. That's OK. I'm using this forum to think out loud... I hope you don't mind. Some of this is redundant with previous posts I've made. I'm still trying to get this all clear. As I see it, pmask has no notion of "tempo" in the traditional sense. "Density" serves a similar purpose, and can be made to change over time, but traditional modes of composition are not supported. OMDE seems to be a more general compositional framework, of which pmask is only one specialized part. OMDE could conceivably support many different approaches to composition. Therefore, I think it should provide powerful tools for working with tempo, since time is the one element common to all music. I'd like to hear discussion of whether the following features are desirable, and proposals for alternative ways to deal with tempo, before we start talking about implementations. What I want to be able to do with tempo --------------------------------------- 1) All tempo calculations are performed at run time ... i.e. not until you ask omde/pmask for some output. Aggregates think of time in beats. Rationale: Maximum dynamism and introspective ability. You can always find the Events at the Nth beat of an Aggregate no matter what time-warping will eventually be done to it. There should also be a method for asking what the absolute time of any particular event would be, so we can find out before we generate output. 2) Tempo control: The syntax is not so important to me, as long as it's easy to specify both simple and sophisticated tempos. The stuff you have in rythm.py looks nice. The csound t statement works pretty well... it can be used for things as simple as "the tempo is now 120" and as complex as "the tempo is 120 for 2 beats, then interpolates to 130 between beats 3 and 5, then suddenly is 40 at beat 5..." etc. Rationale: should be obvious - we want power! The math for doing such time warping is not obvious, but fortunately thanks to linux-audio-dev, I have working python implementation in my old, pre-OO versions of pysco. This could be adapted to OMDE. 3) I want to be able to place a tempo control in an Aggregate that will apply to the start and duration times of all enclosed events or aggregates, RECURSIVELY. This makes things more complicated. To find the clock time for any given event, its beat value must go through the time-warping function of all its parent Aggregates. Rationale: I want the power to create complex rhythmic relationships, and I want it to still be easy to do trivial things. This is the best basic structure I've been able to think of. If only the top-level Aggregate is given tempo controls, then we can easily do traditional kinds of composition. If an Aggregate consists of Aggregates whose tempos are defined as ratios to the parent's tempo, we can do nice polyrhythms even with global accelerando and decelerando. And if each layer of Aggregates have their own accelerando and decelerando, we could have very interesting, complex, evolving time relationships. 4) An Aggregate should also be able to declare itself immune to tempo alteration by its parent Aggregate, in case it wants to skip the procedure described above and exist in an independent time stream. This would mean that, while this Aggregate's start time is still affected by tempo changes in its ancestors, nothing inside it is so affected; as far as its children know, this Aggregate provides the "top level" tempo control. This behavior could simply be toggled by an attribute, such as Agg1.use_parent_tempos = 1 Rationale: OK, this one may not be very important, and it's hard to explain. But it could be a powerful feature. An Aggregate could thus say to its children, "You are free to do anything you wish... but don't start until I tell you." 5) Events could conceivably have other time parameters besides start time and duration. How will these be affected by tempo transformations? This is the responsibility of the particular Event class, but one useful framework might be if the class had a list of which attributes are time-sensitive. At performance time, the Event could go through this list of attributes and calculate the absolute time for each. -- ................ paul winkler ................ custom calendars: http://www.calendargalaxy.com A member of ARMS: http://www.reacharms.com home page: http://www.slinkp.com |
|
From: Maurizio U. P. <um...@ti...> - 2001-10-04 17:15:14
|
On Thu, 4 Oct 2001, Paul Winkler wrote: > Maurizio, I know you said you won't have time to deal with design > issues this month. That's OK. I'm using this forum to think out > loud... I hope you don't mind. > > Some of this is redundant with previous posts I've made. I'm still > trying to get this all clear. > > As I see it, pmask has no notion of "tempo" in the traditional > sense. "Density" serves a similar purpose, and can be made to change > over time, but traditional modes of composition are not supported. To be honest, density is a name I adopted from Cmask but is not a density at all. The temporal density is frequence (which dimensionally is [t]^-1) and the density used by Cmask is a time. In fact in the new pmask.algorithm module (which for backward compatibility is accessible from the pmask module too), contains no longer this term, replaced by dt or something similar. I wouldn't say traditional rhythm is not supported by pmask.cloud(). You can use (I have to clean the syntax, somehow) # kind of zum-zum pa onset = List(*rythm2onset(8, 8, 4)) then use pmask.sequence() instead of pmask.cloud(). Of course you can also do # kind of zum-zum pa pa zum-zum onset = List(*rythm2onset(8, 8, 4), mode='swing-repeat') or if you want a some "feel" onset = List(*rythm2onset(8, 8, 4), mode='swing-repeat') * Range(0.95, 1.1) > OMDE seems to be a more general compositional framework, of which > pmask is only one specialized part. OMDE could conceivably support > many different approaches to composition. Therefore, I think it should > provide powerful tools for working with tempo, since time is the one > element common to all music. > > I'd like to hear discussion of whether the following features are > desirable, and proposals for alternative ways to deal with tempo, > before we start talking about implementations. I feel like that pushing your concept of "tempo" inside the current classes of OMDE you would end carrying inside another concept: pulsation. It is true true that concept of tempo can be applyed to every kind of music if you generalize it enough: it is called event density, which is local. But not all music have a pulsation: some of the have it expressed, some implied, some have no pulsation at all. I think that if you need an Aggregate with tempo, you could use the function-costructor idioma (passing a function as constructor to cloud() or sequence()), like I'm doing right now, and help me to formalize it in the PseudoEvent or MetaEvent classes, as I described in a mail that I'll forward. The ideas you expressed could be all implemented that way, I think. Let me know if it can work for you. Regards, Maurizio Umberto Puxeddu. |
|
From: Paul W. <sli...@ya...> - 2001-10-05 06:38:05
|
On Thu, Oct 04, 2001 at 07:12:46PM +0200, Maurizio Umberto Puxeddu wrote: > To be honest, density is a name I adopted from Cmask but is not a density > at all. The temporal density is frequence (which dimensionally is [t]^-1) > and the density used by Cmask is a time. In fact in the new > pmask.algorithm module (which for backward compatibility is accessible > from the pmask module too), contains no longer this term, replaced by dt > or something similar. > I wouldn't say traditional rhythm is not supported by pmask.cloud(). You > can use (I have to clean the syntax, somehow) (examples snipped) OK, that's all pretty cool. I think I could work with that. > > OMDE seems to be a more general compositional framework, of which > > pmask is only one specialized part. OMDE could conceivably support > > many different approaches to composition. Therefore, I think it should > > provide powerful tools for working with tempo, since time is the one > > element common to all music. > > > > I'd like to hear discussion of whether the following features are > > desirable, and proposals for alternative ways to deal with tempo, > > before we start talking about implementations. > > I feel like that pushing your concept of "tempo" inside the current > classes of OMDE you would end carrying inside another concept: pulsation. Why? Nobody is forced to use tempo or density or whatever you want to call it. I think csound is sensible about this: If no t-statement is found, then times are interpreted as seconds. Remember that seconds are an arbitrary measurement too, and not always appropriate for all time measurements. > It is true true that concept of tempo can be applyed to every kind of > music if you generalize it enough: it is called event density, which is > local. But not all music have a pulsation: some of the have it expressed, > some implied, some have no pulsation at all. Agreed. > I think that if you need an Aggregate with tempo, you could use the > function-costructor idioma (passing a function as constructor to > cloud() or sequence()), like I'm doing right now, and help me to > formalize it in the PseudoEvent or MetaEvent classes, as I described > in a mail that I'll forward. The ideas you expressed could be all > implemented that way, I think. Now this is interesting. I haven't seen this mail yet, but MetaEvent is a very provocative name. Looking forward to it! -- ................ paul winkler ................ custom calendars: http://www.calendargalaxy.com A member of ARMS: http://www.reacharms.com home page: http://www.slinkp.com |
|
From: Maurizio U. P. <um...@ti...> - 2001-10-04 20:36:52
|
On Wed, 3 Oct 2001, Paul Winkler wrote: > On Wed, Oct 03, 2001 at 03:52:40PM +0200, Maurizio Umberto Puxeddu wrote: > > On Mon, 1 Oct 2001, Paul Winkler wrote: > I'd still like to discuss whether objects should be responsible for > their own start time, or delegate that to a parent Aggregate. When > you get a chance, I'd like to hear your reasoning for making each > event responsible for its own start time. > > The only argument I can see *against* giving this responsibility to > the parent (the containing Aggregate) is that it requires you to have > a top-level Aggregate to control your composition's overall > structure. This might be seen as inconvenient; "I know when this > object should start, I want to say so when I create the object." This is not a problem, with me at least. The problem is an that you can't perform onset-related operations on an object without interacting with its container (as a trivial example, translation). At the moment, in OMDE you can put an object in a container and still intermixing direct operations on the object and operations on the container as a whole, that is: e = Event() a = Aggregate(e, f, g , h ,i) a.strech() e.translate_relative(-5) How do you perform a translation of an object in your way? a.translate_object_relative(a, -5) Doesn't works, because, as you said, you want to have several copies of the same event. You have to do something like a.translate_object_relative(123, -5) where 123 is probably the index of the object in the list of tuples (onset, object) like a.list This is good for a GUI, where you click on the windows, calculate the coordinate of an event, find it on the list and keep its index. Not so good with a script. You should have to tag one to one each event... > As further purely anecdotal evidence, I'll note that the author of > Blue does it my way. :) In fact Blue its GUI driven! Are you in contact with him or did you read the sources of Blue? I always thought of Blue as the obvious user interface for OMDE/pmask. Maurizio Umberto Puxeddu. |
|
From: Paul W. <sli...@ya...> - 2001-10-05 06:17:46
|
On Thu, Oct 04, 2001 at 10:34:21PM +0200, Maurizio Umberto Puxeddu wrote:
> On Wed, 3 Oct 2001, Paul Winkler wrote:
>
> > On Wed, Oct 03, 2001 at 03:52:40PM +0200, Maurizio Umberto Puxeddu wrote:
> > > On Mon, 1 Oct 2001, Paul Winkler wrote:
> > I'd still like to discuss whether objects should be responsible for
> > their own start time, or delegate that to a parent Aggregate. When
> > you get a chance, I'd like to hear your reasoning for making each
> > event responsible for its own start time.
> >
> > The only argument I can see *against* giving this responsibility to
> > the parent (the containing Aggregate) is that it requires you to have
> > a top-level Aggregate to control your composition's overall
> > structure. This might be seen as inconvenient; "I know when this
> > object should start, I want to say so when I create the object."
>
> This is not a problem, with me at least.
> The problem is an that you can't perform onset-related operations
> on an object without interacting with its container (as a trivial
> example, translation).
> At the moment, in OMDE you can put an object in a container and
> still intermixing direct operations on the object and operations on the
> container as a whole, that is:
>
> e = Event()
>
> a = Aggregate(e, f, g , h ,i)
>
> a.strech()
> e.translate_relative(-5)
I'm guessing that you mean " e's start time is now 5 less than it
was".
Oh, wait - I see, you're referring to Event.move_relative from
score.py.
> How do you perform a translation of an object in your way?
>
> a.translate_object_relative(a, -5)
^
Do you mean e ?
> Doesn't works, because, as you said, you want to have several copies of
> the same event.
Why not? Just look through the sub-objects and test if each one "is"
e. This will have exactly the same effect. If copies (rather than new
references) were made, they wouldn't be changed in my approach or in
your approach. I don't see a difference here, except that my approach
is much less efficient if there are many sub-objects.
> You have to do something like
>
> a.translate_object_relative(123, -5)
>
> where 123 is probably the index of the object in the list of tuples
> (onset, object) like
>
> a.list
>
> This is good for a GUI, where you click on the windows, calculate the
> coordinate of an event, find it on the list and keep its index.
> Not so good with a script.
Point taken. In my proposal, it is potentially hard to find an event
inside an aggregate if there are multiple references to it in there.
In your approach, that just wouldn't happen; multiple references would
serve no purpose since they by definition start at the same time and
do the same thing, so the composer just wouldn't do that.
On the other hand, it's still quite easy to lose track of individual
events in your approach; this could happen anytime an Aggregate
contains anonymous Events, e.g. created by pmask.cloud(), or if the
composer does something like
a = Aggregate(Event(), Event())
It could also happen if the name for the event in question gets
re-bound after the Aggregate is created.
But having said that, I concede that you have a slight advantage here.
If we *really* need guaranteed ability to find an event within an
Aggregate, no matter what happens, then we could always create an
Aggregate subclass that stores its sub-events in a dictionary, so each
one must have a unique key.
As for the organizational clarity of my approach, I've realized that
it can be had via a factory function:
def needs_a_good_name(*args):
result = Aggregate()
for t in args:
at, event = t[:]
e = copy.deepcopy(event)
e.onset = at
result.add(e)
return result
> > As further purely anecdotal evidence, I'll note that the author of
> > Blue does it my way. :)
>
> In fact Blue its GUI driven!
> Are you in contact with him or did you read the sources of Blue?
Neither - I read the PDF documentation, and in fact I read it wrong!
From the docs:
""" In the lower area, the soundObject s editing interface is
shown. For a genericScore object, it is a text area for inputting
i-statements. The score input into a genericScore are always from time
zero. However, when a CSD file is generated, the times of the
i-statements will have the start time of the soundObject added to it
... """
So in fact, the input here is just some text representing i
statements, and they don't have to start at zero. So in fact I have no
idea what happens internally in Blue with nested objects.
> I always thought of Blue as the obvious user interface for OMDE/pmask.
It's definitely an appealing approach. But one great thing about doing
this work in python is that we can have as many interfaces as we like;
it's easy enough that it's not inconceivable to develop a custom
experimental GUI for each composition!
--
................ paul winkler ................
custom calendars: http://www.calendargalaxy.com
A member of ARMS: http://www.reacharms.com
home page: http://www.slinkp.com
|