Menu

Class Structure

Enduser
2004-01-01
2004-02-01
  • Jeremy Evans

    Jeremy Evans - 2004-01-01

    The class structure that I would like to use is..
    -TModulePlayer -> Component to be used on form
    -TSongData -> the Parent to classes such as TModData, TItData.
    -TRenderer -> The parent to TWinRenderer, or TOpAlRender.

    Any Special rendering required for a specific type such as S3m instruments Should be written into the renderer. Any comments?

    -Jeremy

     
    • Marten van der Honing

      TModulePlayer should also function without a form e.g. console mode.

       
      • Jeremy Evans

        Jeremy Evans - 2004-01-02

        Right.. The component will not rely on the form in any way. It will be able to be instantiated without an owner class assigned. The only reson really to make it a component is for formed projects that will allow some published properties to be modified.

        -jeremy

         
    • WILL

      WILL - 2004-01-03

      I can't say that I'm too happy with this structure's naming conventions. For one, 'TModulePlayer' should be 'TModuleMixer', 'TOpAlRender' should be 'TOpenALRender' and 'TITData' to 'TITData'. Acronyms should use all caps and we should try to use the full word or name if it is simple. This will help keep the code from getting cryptic and confusing to remember/code with.

      Also do you mean to make the currently dubbed "TModulePlayer" into a TComponent or TObject class decendant? TObject should give us more than enough to work with and is slighty smaller too, I believe.

       
      • WILL

        WILL - 2004-01-03

        I think that the command to 'Render' the next audio feed from the curently loaded module should be ran from the actual declared object that it was loaded from.

        ie. When using the library I would have code set something like this:

        --- Start Of Code ---
        program ThirdPartyModPlayer;

        uses
          openmod, {etc};

        var
          ModMixer: TModMixer; {<-- or whatever we call it}
          AudioStream: TStream;
          AudioBufferSize: Integer;
          OutputBufferSize: Integer;

        procedure Timer.Timer();
        begin
             if ({sound hardware is done playing last buffer}) then
             begin
                  {get next audio buffer output frame}
                  if (not ModMixer.Rendering) then
                       OutputBufferSize := ModMixer.Render(AudioStream, AudioBufferSize); // if -1 then nothing to render
             end;
        end;

        begin
             ModMixer := TModMixer.Init({set things like what kind of mixer to use, etc});
        end;
        --- End Of Code ---

        This is how I see the openMOD library to function effectively. Requiring only one object to ultimately be used in the end user's code. This is what I think we should shoot for. I know I wouldn't want to use it any other way.

         
    • Jeremy Evans

      Jeremy Evans - 2004-01-03

      In what I'm thinking you will still be able to do as you suggest WILL, I was just after a more uniform model. I.E. being able to use it on the form designer or being able to use it at runtime. If you want we could start with a lower object that will be more like you suggest that will descend from TObject and then build more of a jutbox component that can be used on a form and command the player component.

      -Jeremy

       
      • WILL

        WILL - 2004-01-03

        This is actually waht I believed we were doing. Was it not? We can go further later on and make an actual player component, etc if we anted, but wouldn't it be better to make a simple loader/mixer model first and can be used on it's own? I think that this will allow us to have a more functional Magic Black Box effect rather than a complex picky monster on our hands. I've seen too many of these projects get dropped because of this effect.

         
    • Jeremy Evans

      Jeremy Evans - 2004-01-03

      -k- Well then I'll start with a loader like structure. I'll post an example when I've get a sec.

      -Jeremy

       
      • Marten van der Honing

        Some thoughts on the TModuleData class details:

        TModuledata

        consists of

        Pattern: array of TPattern; {the blocks a modfile consists of}
        Order: array of integer; {orders what patterns to play when 0=1 1=2 2=3 3=3 4=3 5=2}
        Instruments: array of TSample; {the samples}

        ----------------

        TPattern

        consists of

        Channel: array of TChannel {could be 0..3 for a 4 channel mod}

        ---------------

        TChannel

        consists of

        Bar: array of Tbar {could be 0..63 for a 64 bar (note positions} long pattern}

        ---------------

        TBar

        consists of

        Instrument: integer;
        Note: integer;
        Effect: integer;
        Param: integer;

        ---------------

        Access to a note would be like:
        module.pattern[module.order[0]].channel[0].bar[0].note

        Of course the above classes should use properties for access but the exampele above is still valid.

         
    • Jeremy Evans

      Jeremy Evans - 2004-01-07

      Yes I think that that is the most logical of looks here is how I thing we should start. Lemme know of any other changes any would like to see. Obviously not all items are there yet but as I said I think this is the best start.

      Code begins here
      ---------------------------------------
      unit OpenMod;

      interface

      Uses
        SysUtils, ModData;

      type
        TModState = (modPlaying, modStopped, modPaused, modLoaded);

        TOpenMod = class(TObject)
        private
          FModData: TSongData;
          FModRenderer: TModRenderer;
          FState: TModState;
          procedure SetState(const Value: TModState);
        public
          function Play: boolean;
          function Pause: boolean;
          function Stop: boolean;
          function OpenFile(FileName: String): boolean;
          constructor Create(AFilename: String); overload;
          constructor Create; overload;
          destructor Destroy; override;
          property State: TModState read FState write SetState;
        end;

      var
        //Globals.

      implementation

      { TOpenMod }

      constructor TOpenMod.Create(AFilename: String);
      begin
        //Create and open A file
      end;

      constructor TOpenMod.Create;
      begin
        //Create Without opening a file
      end;

      destructor TOpenMod.Destroy;
      begin
        //Free and Nil all Possable instantiated sub Object
        inherited;
      end;

      function TOpenMod.OpenFile(FileName: String): boolean;
      begin
        //Open file return if a Data object could be created
      end;

      function TOpenMod.Pause: Boolean;
      begin
        //Pause playback
      end;

      function TOpenMod.Play: Boolean;
      begin
        //Play Data
      end;

      procedure TOpenMod.SetState(const Value: TModState);
      begin
        FState := Value;
      end;

      function TOpenMod.Stop: Boolean;
      begin
        //Stop playback.
      end;

      end.

      unit ModData;

      interface

      Uses
        Sysutils, Classes;

      Type
        TSongData = class(TObject)
        protected
          FData: TMemoryStream;
        public
          constructor Create(AFileName: String);
          destructor Destroy;
        end;

        TModData = class(TSongData)
        private
          function GetName: String;
          function GetSig: String;
        public
          property SongName: String Read GetName;
          property Signature: String Read GetSig;
        end;

      implementation

      { TSongData }

      constructor TSongData.Create(AFileName: String);
      begin
        FData := TMemoryStream.Create;
        FData.LoadFromFile(AFilename);
      end;

      destructor TSongData.Destroy;
      begin
        FreeAndNil(FData);
      end;

      { TModData }

      function TModData.GetName: String;
      var
        tmpStr: String;

      begin
        tmpStr := StringOfChar(' ', 20);
        FData.Seek(0,0);
        FData.Read(tmpStr, 20);
        Result := tmpStr;
      end;

      function TModData.GetSig: String;
      var
        tmpStr: String;

      begin
        tmpStr := StringOfChar(' ', 4);
        FData.Seek(1080, 0);
        FData.Read(tmpStr, 4);
        Result := tmpStr;
      end;

      end.

       
    • Jeremy Evans

      Jeremy Evans - 2004-01-07

      My Code was indented properly :-/.....

      Ah Well

       
    • WILL

      WILL - 2004-01-08

      I like it. Quick, post it before I start to get picky. ;)

      Actually I'd have OpenFile be LoadFromFile to match with ObjectPascal method conventions. Uh oh.. already started. ;)

       
    • WILL

      WILL - 2004-01-08

      I do have one question though. Would it not be best to seperate each module format into it's own source file?

      ie. TSongData in fdata.pas, TS3MData in fs3mdata.pas, T669Data in f669data.pas, TITData in fitdata.pas, etc...

      For CVS and development purposes it may be easier for us to share work-loads and add new formats to the project.

       
    • Jeremy Evans

      Jeremy Evans - 2004-01-08

      The main reason jto keeping them in the same unit is so that anything we decide to put into the protected portion of TSongData is still accessable by derived classes. If they are seperated out the fdata needs a public accessor method. The other reason is I'm kinda using a borland convention here where all like classes are in the same unit.

      -Jeremy

       
    • Jeremy Evans

      Jeremy Evans - 2004-01-08

      Yes we can chand to loadFromFile.

       
    • Marten van der Honing

      i think it is best to use loadfromstream as the main loading part. loadfromfile would be a wrapper around loadfromstream. That way it will be easier to load a mod from a zip file. (no need to write it to disk first)

       
    • Marten van der Honing

      also take a look at this structure: https://sourceforge.net/forum/message.php?msg_id=2363669
      it also above here somewhere...

       
    • Jeremy Evans

      Jeremy Evans - 2004-01-08

      I will change the class definition a little to allow that it's not a big change. Also if you would like the current version is in cvs now. I want to finish TmodData but any one can add TwhateverData kto it if you want. I will also make the change to TSongData also but it should not effect any other changes anyone would like to make.

      -Jeremy

       
      • WILL

        WILL - 2004-01-10

        Hmm... I think we should be continuing this in the Developers forums.

        But as for the CVS, I don't see any files posted. Maybe I'm not looking in the right place? Can you double check that it submitted properly? Thanks. :)

         
    • WILL

      WILL - 2004-02-01

      You'll notice that I've added the S3MData.pas unit as a test(Finally got CVS configured properly). I have to double-check that this follows our set library structure plan(I may have had a small laps and placed the code in a wrong file). Anyhow... I am ready to do some coding now commits and all.

       

Log in to post a comment.

MongoDB Logo MongoDB