Am 08.02.2013 21:54, schrieb Tim E. Real:
> On February 8, 2013 03:20:24 AM Tim E. Real wrote:
>> On February 6, 2013 12:04:46 PM Florian Jung wrote:
>>> Am 06.02.2013 10:01, schrieb Tim E. Real:
>>> do you understand why we need so individually stretch every event?
>>
>> No.
>> Because the 'intrinsic' tempo map that we will store with a wave
>>  will be static and will never change unless the user re-taps or clears it
>>  or re-draws it on some special graph or whatever.
>> Every wave event using that wave, no matter where its position, only needs
>>  that intrinsic tempo map, to compare with the global tempo map and apply
>>  the differences back to the converters.
>> That goes as well for even shared wave events in clones and non-clones.
>>
>> And moving a wave event around does not change its intrinsic tempo map.
> 
> Crud. It takes time to call up the vast repository of knowledge and experience
>  and formulate an answer and sometimes I misunderstand.
> 
> You aren't referring to the intrinsic tempo maps. 
> 
> You are referring to the fact that you need independent stretched
>  copies of each wave event.
> 
> And that cannot easily be done with shared event lists.

exactly.

> So you want independent event lists, even for so-called clones.

that was my idea, yes.

> 
> I was looking at it from my realtime point of view.
> I could certainly benefit from independent event lists as it would sure
>  relieve my headache of finding out what wave part contained them.
> But I believe in my case independent lists would not be absolutely required.
> 
> In your case yes, you could work around it but yep, basically it's required.

indeed we could work around this, we have three alternatives:

1 independent event lists
2 shared event lists, every event has a map<Part*, some_context_t>.
  Event::process() gets a Part*, and upon every call it looks up in the
  map
3 shared event lists, every part has a map<Event, some_context_t>.


1 is good, except that we store some data duplicated, and changing stuff
will take longer (O(n_parts) instead of O(1))

2 and 3 are both bad design. 3 arises the problem of how to use Event as
a key in a map. It'd need a operator<.
2 makes songs with many clones slow, because lookup is in O(log(n_clones)).
both 2 and 3 add massive overhead to every single process() call (even
if we have no clones! it still needs to lookup in the map)

1 adds overhead in the case of multiple clones, and no overhead at all
when there are no clones. the overhead added here is only while editing,
and IMHO should be unnoticeable; will need to verify this.

i strongly vote for 1: it unifies a sane design (where objects are
self-contained, and do not require their parents to manage any data
which is only used by the child), hopefully decent performance (best
performance while playing, and a hopefully unnotable impact on editing
clones).

do you have more ideas? what do you prefer? and why?

> 
> There is another elephant in the room:
> 
> Even in completely independent event lists containing independent
>  events, the events can refer to the same EventBase pointer.
> That is, they eventually point to the same SndFile or midi event.

yup. that saves us from duplicating too much data.


> How can we keep the original wave while keeping a stretched copy as well?
> I don't think we can keep /only/ a stretched copy because trying to un-stretch
>  it does not return us to the original wave - there will be losses - so I  
>  think we need to keep the original around.

have a look at the picture i mentioned in the other mail: SndFile (or
WaveFile) will need to have functions like "createStretchProfile" and
"dropStretchProfile".

create will return an integer-id of the profile, and SndFile holds a
std::Vector with the profiles+context (which can be accessed in O(1),
not in O(log n) :) ).
basically, the part tells the event "stretch using this extraneous
tempomap", the event fordwards this to the sndfile, and stores the
returned handle (in our non-shared event list).

whenever we read audio data, the Event tells the soundfile "hey, get me
the data from range to range, using this stretch profile."

And SndFile will do some magic to fulfill the request. It could possibly do:
- recalculate it on-the-fly
- look it up in its 500kb-large small cache
- look it up in a on-disk-cachefile if the user wishes so
- return only silence if the user wishes to never do realtime-stretching
- whatever.




--------------- later addition: ----------------

the above was for precalculated mode (as i'd like to do it). but if we
want realtime mode (which is needed with external time synchronisation),
we'd need the following addition:

- every wave event holds an instance of a stretcher (we might do some
  pooling in the background, though.)
- when realtime data is demanded, the WaveEvent::process_the_data() call
  will get two parameters. "how many samples to read from the original
  wave" and "how many sample shall the output have".
- it must then change the stretch ratio accordingly (we can do this
  because this stretcher is in Live-mode), process frames, possibly
  implement a small FIFO (if we request 1000 frames from our stretcher,
  we might get only 997 or 1004.), and possibly adapt the stretch ratio
  in order to compensate for stretching errors:
  (if we call this 100 times, and every time we're getting 997 instead
  of the desired amount of 1000 frames, we need to request for 1100
  frames at some point, so the accumulated error doesn't get too big.)

basically, that's not too hard if we already have a place to store "per
event-and-part" data. i.e., non-shared eventlists.

------------ end of addition ----------


> 
> Ah, I think you're saying we will have independent event lists, yes, 
>  and each Event contains the additional info we need, also we know 
>  what wave part contains it, and yet the Event's EventBase pointer 
>  /can/ still be shared under normal circumstances.
> OK Interesting. If I have this correct. 
> Am I wrong, can it work. Lemme think some more...

you have it correct, and what you wrote is true.


> The other thing I wanted to point out is that clones are often used 
>  in pattern-based songs.
> Someone might have a hundred clones of a drum pattern for example.
> So changing one note in a clone would force the app to do the other 
>  99 clones. Might be slow? 
> Especially with our synchronous msg*** system maybe getting in the way? 
> But then, your undo operations lists help there. Maybe a non-issue? Or not...

i'm hoping that using operation lists, this should be done very
(unnoticeably) fast, yeah. If it's not fast, we'd have a problem.

> 
> So what's the solution?
> Hm, tough dog.
> Well you can see why I have reservations about doing this.
> Radical. But if we must...
> Let's make sure we examine /all/ the angles and expose any gotcha's 
>  and fight the drawbacks.

i fully agree.



> 
> Tim.
> 
> ------------------------------------------------------------------------------
> Free Next-Gen Firewall Hardware Offer
> Buy your Sophos next-gen firewall before the end March 2013 
> and get the hardware for free! Learn more.
> http://p.sf.net/sfu/sophos-d2d-feb
> _______________________________________________
> Lmuse-developer mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/lmuse-developer
> 


Attachment: signature.asc
Description: OpenPGP digital signature

------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013 
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
Lmuse-developer mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/lmuse-developer

Reply via email to