> On Fri, Feb 25, 2011 at 5:58 AM, Hudak, Paul <[email protected]> wrote:

>> First, you can label any Music value with any instrument.  For example:

>>

>> instrument Flute m1 :=: instrument Violin m2

>>

>> This is a Music value that plays m1 with a flute in parallel with m2 with a

>> violin.  But Flute and Violin are abstract, and later they can be mapped to

>> a standard MIDI instrument, or mapped to an instrument you design yourself

>> at the signal processing level (for example, via the renderSF function

>> mentioned below).  Currently you can't mix MIDI and signal functions - they

>> must all be either one or the other - but that's something we'd like to

>> fix.  "Note attributes" allow passing arbitrary information from the score

>> to the instrument (like csound's pfields), which of course is just ignored

>> by MIDI.

>

> Just out of curiosity, what benefits do you see from this extra layer

> of abstraction?  In other words, why write:

>

> score = instrument Flute m1

> realize score [(Flute, myFluteInst)]

>

> rather than

>

> realize (instrument myFluteInst m1)



MyFluteInst is essentially a signal function.  So how would you do MIDI 
instead?  That's the reason for the indirection via an association list.



> To me it just seems like an arbitrary name to pick (what if your

> instrument doesn't fit into the predefined names, or if you have

> thousands of instruments, one per note, or if 'realize' gets an

> instrument it doesn't understand?).



The names are somewhat arbitrary, but actually match the General MIDI 
instrument names.  If you prefer a different name, the Instrument data type has 
a "Custom" constructor, so you can write, for example:



instrument (Custom "my crazy instrument") m



If you really do need a thousand instruments, I would argue that you shouldn't 
name them, you should pass an argument (via a NoteAttribute) to a smaller 
number of instruments that affect the sound in some way.



If "realize" gets an instrument it doesn't understand, you get an error -- but 
that's what I would expect.



>> Second, as in Haskore, there is an interpretive layer between Music values

>> and the back-end.  Specifically, there is something called a Player than

>> generates an abstract Performance from a Music value.  A user can define her

>> own Player - for example, you can define a "piano player" that interprets

>> legato differently from a "violin player", or you might define a "jazz

>> player" that introduces a "swing feel".  Like instruments, you can have more

>> than one player playing in the same composition.  A lot can be done at the

>> Performance level that is much more difficult to do at the Music level, so

>> it provides a convenient level of abstraction.

>

> This sounds like something I've noticed, and if it's the same thing, I

> agree.  But I disagree that you need to separate orchestra and score

> to get it.  Namely that notes are described hierarchically (e.g.

> phrase1 `then` phrase2 :=: part2 or whatever), but that many musical

> transformations only make sense on a flat stream of notes.



That's exactly what I'm saying, so I guess we must agree :). A Music value is a 
hierarchical structure, whereas a Performance is a linear structure.  In 
Euterpea you have a choice of modifying one or the other.



> For example, decide which note a string would be played on and pick a

> corresponding corresponding base note + bend.  You can't do this

> without a memory of which notes have been played (to know currently

> sounding strings) and maybe a look a little ways into the future (to

> pick between alternatives).  Hierarchical composition has no access

> the previous and next notes, so it winds up having to be a

> postprocessing step on the eventual note output stream, which means

> you have to have something in between the score and the sound.  By why

> be limited to one one instance of this player and a static score ->

> player -> sound pipeline?



Not sure what you mean here.  You can define and use as many Players as you 
like in a composition.



> The way I have it set up, this postprocessing (maybe like a Player in

> Euterpea) is interleaved in the score itself.  So, say if I want to

> play a given run with a swing feel, I can wrap 'swing' around just the run.



If you prefer to write "swing" at the Music level, there is nothing to stop 
you.  But as we noted above, some things are done more easily at the 
Performance level.



>  There's no need to put a "swing" attribute into the score type

> and then teach the Player how to interpret "swing"---this is what I

> would call having to set up knobs that you get when orchestra and

> score are separate.


But I think the source code at the music level would look the same in your 
version or mine, i.e. something like "swing m".  The difference is that your 
version would actually modify m, whereas my version would delay it until the 
player got a hold of it.



> And then this swung output can be further

> composed as part of the score, which I believe is unavailable once you

> get to Player, e.g. tweak notes after the swing is applied if I decide

> one should be earlier or later.  If I understand correctly, in

> Euterpea you would have to do this tweaking after the Player, and

> couldn't do it in the score, unless you set up a "post-swing-teak"

> attribute and added support to the Player.  It doesn't seem like that

> far-fetched of a thing to need to do.

> ...

> ... Maybe another

> way of putting it is that different interpretations of abstract

> instructions like legato are not necessarily always along instrument

> (piano vs. violin) lines: it may vary from phrase to phrase, or

> section to section.



Not sure I understand your point, but perhaps I didn't make it clear that a 
Player is orthogonal to an Instrument.  So I can write, for example:



player p1 (instrument i1 m1 :=: instrument i2 m2) :+:

instrument i3 (player p2 m3 :=: player p3 m4)



> This is analogous to wanting to make a reversed instrument and then

> write score for that instrument, without having to run the render

> cycle twice.



I am unclear as to what you mean by "reversed instrument", but I wanted to 
point out that most sound synthesis algorithms are "causal", meaning that the 
current output depends on past output (for example filtering, reverb, etc.), 
but not on any future output.  Therefore to reverse a signal you would have to 
generate the entire result, save it in a data structure, and then reverse it.  
Euterpea doesn't currently allow this, since our focus has been on making 
things run fast, and storing things in data structures is anathema to that.  
But in principle it seems easy enough to do.



On the other hand, reversing a Music value or a Performance value is trivial.  
And if you reverse a Music value, the hierarchical structure is preserved.



> I'm not totally convinced the integration is valuable, but seeing as

> almost all other systems don't have it, it seems interesting to

> experiment with one that does and see where it leads.



I agree.



Best,  -Paul


_______________________________________________
haskell-art mailing list
[email protected]
http://lists.lurk.org/mailman/listinfo/haskell-art

Reply via email to