On Wed, 5 Aug 2009, Jakob Lund wrote:
>>
>> Well, when I look at the code (so far) there's not that much to it. 90% of
>> the real heavy lifting is being done by TransportPosition and the functions
>> in song_helpers.cpp. If things start to get too much more involved... I
>> would rather share code through class inheritance or aggregation rather
>> than mediation between classes.
>>
>> And what you propose in that last paragraph there *is* a 3-way mediation.
>> What we have currently in Hydrogen is also a 3-way mediation. "This is the
>> transport... but we need this *other* transport to think he's the
>> transport... and in *this* situation we add this band-aid between them to
>> keep everyone happy..."
>>
>
> Can you please explain that a little more?
>
> If I understand correctly, the term 'aggregation' describes the
> technique used within H2Transport, which is treated (in sequencer code)
> as the actual transport, but really delegates the work to other
> transport objects.
If a transport class is doing something complex (like following JACK, MTC,
MIDI Clock, etc.), it needs a fallback if the transport source fails or
gives invalid data. Right? One way it could be implemented is:
class MidiClockTransport {
SimpleTransportMaster m_fallback;
};
This aggregates the other implementation into this implementation.
By inheritance (you didn't ask... but I'm explaining just in case), the
fallback could be provided (somehow) like this:
class MidiClockTransport : public SimpleTransportMaster {
//...
};
Or, more realistically:
class MidiClockTransport : public DefaultTransportImplementation {
//...
};
class SimpleTransportMaster : public DefaultTransportImplementation {
//...
};
The difference between this and what you have suggested is this: I'm not
_requiring_ an instance of a specific class or specific code or anything.
I'm requiring that the Transport implementations be reliable. If they
make themselves reliable by having a private copy of a different
implementation, or by inheriting from a different implementation... it's
up to *that* implementation.
Why would this be important? I think that this makes it simpler for
everyone. No transport has to negotiate with any other transport.
H2Transport's sole purpose it to manage transport implementations for
class Hydrogen, and everyone else just cares that they're getting
*Transport. If I go to write a transport that nobody ever conceived of...
I don't have to find some way to fit that idea into a 3-transport
mediation scheme. There's one boss. One authority. And he better be
right. :-)
> I don't know what is meant by 3-way mediation (which is why I made that
> lame joke before) - and why does what I suggest imply... that?
Currently, when JACK is the master, it looks like this:
Application <--> Transport <--> Jack Transport Interface
(I'm going by memory... so don't grill me on details) -- Both the
application and the Jack Transport Interface are making behind-the-scenes
adjustments to the transport. IIRC, even places in the GUI and
hydrogen.cpp are adjusting the tick. Then there's "realtime ticks" and
"current ticks" and all that stuff. And we have something like
"tick_offset" that is maintained and manipulated. That is, "Jack says
we're on tick 5... so that means we're on 5 + tick_offset = 65." (Maybe
it's frame offset... I don't recall.) Things are even more fragile when
we export this info to be the jack time master. (And this is even broken
because we don't handle the case where someone *else* has taken over as
time master... so we keep marching to our own drum.)
Then, you've been suggesting:
Application --+-- TheRealTransport
|
+-- TheOtherRealTransport
Which seems similar... even if you do it like this:
Application --- H2Transport --+-- TheRealTransport
|
+-- TheOtherRealTransport
If we require this set up... I'm pretty sure that these two transports are
going to have a hard time communicating with each other effectively.
So, that's why I think there should be ONE transport (at a time)... even
if it means copying code among implementations (which I don't think is
necessary).
> IMO the current h2 is broken because the original design was too simple,
> and was repaired upon for too long using 'band-aid' style hacks. The new
> design should repair that, but without getting unnecessarily
> complicated.
This is valid. It also looks to me like the original concept was an
ALSA-based sequencer where everything is happening "now" rather than
processing a chunk at a time. When JACK showed up, it looks like Hydrogen
was converted to an interrupt-based approach (using a process()
callback)... but tried to maintain the transport of the old stream-based
approach. I think this is why it's broken.
But I don't think what I'm proposing is complicated at all. It's pretty
simple: One reliable transport.
> What I was trying to do was to make tempo changes during playback
> (through the UI) possible, but I couldn't figure out where to put the
> code that looks into the Song to check its tempo... Transport being
> driven by SimpleTransport class, that was my first choice but that
> didn't seem to make sense, for the reasons I've tried to explain.
SimpleTransportMaster gets the current tempo by asking the Song. So, if
you do pSong->setBpm( 120.0 ), it will take effect in the transport on the
next cycle.
EXCEPT THAT.... there's a bug where this is not happening. :-)
There should be a line in processed_frames() where we have:
d->pos.beats_per_minute = d->song->__bpm;
I'll get that fixed....
Peace,
Gabriel
------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day
trial. Simplify your report design, integration and deployment - and focus on
what you do best, core application coding. Discover what's new with
Crystal Reports now. http://p.sf.net/sfu/bobj-july
_______________________________________________
Hydrogen-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/hydrogen-devel