Jim Leonard schreef:
> For a hobbyist project, I'm writing a music composer, and I really
> want to make it object-oriented because the data really lends itself
> to OOP for reasons I'll explain later. The only problem is that,
> while I'm a competent Pascal programmer, I've never done OOP before.
> My environment is Turbo Pascal 7.0. Before I lay out the details, I
> want to stress this is not a homework assignment :-) I am not asking
> for code, just the normal, best-practices way to do what I want to
> accomplish.
>
> I thought of creating a "song" object with the ability to enter notes,
> save/load the song data, etc because it makes perfect sense; the
> methods can validate the data and generally abstract the song. But
> the song needs to play, and that's where I get stuck on the proper way
> to program in OOP to access the song data. Should I:
>
> - Make a new "player" object that inherits the song object (so that it
> can directly reference the song data structures)?
> - Make a new "player" object that calls the song object's methods to
> pass the data back and forth?
> - Have the song object pass a pointer to the note data to be accessed
> by the player object? (that seems like it's defeating the whole
> purpose of OOP)
> - Build the playback routines directly into the song object, so that I
> have a single object with a gazillion methods?
>
> The program needs to be able to play the song, not only for one
> particular output device, but several. That means the playback
> routines need to be VIRTUAL so that I can replace them with methods
> for additional sound devices as I code them. It is that requirement
> that has me confused about the proper direction to take.
>
> I was leaning toward this:
> A song object;
> a player object that inherits the song object and contains only
> generic VIRTUAL playback methods;
> a device-specific object that replaces the virtual methods with
> methods for that device's hardware.
> I figure that way I can get direct access to the song's data
> structures without "exposing them to the outside", and I can keep
> building on previous code as necessary.
>
> Does that sound like the right way to go, or am I barking up the wrong
> tree?
Interesting project. Controlling the PC sound possibilities in TP or BP
is not easy. In don't know how you would organise this. Perhaps Delphi
will give you more possibilities here. But you are very right that this
kind of program requires OOP.
If you can get your hands on a copy of Borland Pascal with objects V7.01
I would strongly recommend this instead of TP7. Try to find a legal
copy, but for educational projects no one will care if you try to find
the BP.Zip installation file somewhere
Inheritance is very handy if there are several enteties that all need to
be treated more or less in the same way.
E.g. A note and a tone have the parameter "duration" in common, but a
note has the added parameters heigth, volume, rampup and rampdown etc.
So it is logical that TNote is a descendant of TTone, which in itself
descends from Tobject. Both will have a play method that can be used,
but TTone will override the Play method of TNote.
Next is to define the Melody object, which can best be a descendant of
Tcollection. The collection can be filled with objects either being note
or tone.
The common factor between violin, piano and drum is that they are all
different kinds of musical instruments. So if you want to load them in a
player there should be an inherited common method e.g. Play.
type
PInstrument:^TInstrument;
TInstrument:object(tobject)
melody:tmelody;
constructor init:
destructor done;
procedure play; virtual;
end;
implementation
constructor TInstrument.init;
begin
melody.init;
end;
Procedure TInstrument.play;
begin
abstract; {Always to be overridden by a descendant}
end;
destructor TInstrument.done
begin
melody.done;
end;
The abstract statement will generate an error on execution. This
procedure should always be overwritten by the actual instruments of
piano, violin and drum which are descendants of TInstrument. Each of
them holds different sound samples and different ways on how to connect
the tone and duration to the sound sample.
The player will probably have a list of instruments that can all play
simulataneously. In order to call a method of an instrument of unknown
implementation, you can simply call the abstract method of the parent.
Something like
Procedure tplayer.play
procedure plee(p:pinstrument);far;
begin
p^.play;
end;
begin
foreach(@[EMAIL PROTECTED]
);
end:
But the puzzle is entirely yours. There are more ways to do what you want.
Good luck
-- Femme


|