TRAMUGENCLASS.PAS

{****************************************************************

                       RAMUGEN      ENGINE

 ****************************************************************

    This is the default engine for the TRamugen class.
    It's modelled on Ramugen V.1, which was the non-OOP version
    of Ramugen. If you don't want to use this type of engine,
    use TCustRamugen instead of TRamugen for your application.

    It's also possible to over-ride the TRamugen component's engine
    partially or completely.
    To over-ride completely, just assign your own object method to
    TEO_01_PlayNote event. ("Total Engine Override")
    To over-ride only parts of the engine, use the various PEO events.
    ("Partial Engine Override")

    The implementation of the Ramugen Engine begins with a "Template method"
    which delegates the action to the various engine events.
}


procedure TRamugen.MIDITimerDefault(Sender : TObject); //"Template method" pattern
begin
  if Assigned(FEngineInitialise) then FEngineInitialise(Self);
  if Assigned(FEngineStopNote) then FEngineStopNote(Self);
  if Assigned(FEngineCheckPlaying) then FEngineCheckPlaying(Self);
  if Assigned(FEngineLandMarkCheck) then FEngineLandMarkCheck(Self);
  if Assigned(FEnginePitch) then FEnginePitch(Self);
  if Assigned(FEngineLandMark2) then FEngineLandMark2(Self);
  if Assigned(FEngineKey) then FEngineKey(Self);
  if Assigned(FEngineAmplitude) then FEngineAmplitude(Self);
  if Assigned(FEngineDuration) then FEngineDuration(Self);
  if Assigned(FEngineRest) then FEngineRest(Self);
  if Assigned(FEngineStartNote) then FEngineStartNote(Self);
  if Assigned(FEngineFinalise) then FEngineFinalise(Self);
end;

//main engine sub-methods

procedure TRamugen.EngineStopNote(Sender: TObject);
begin
  StopNote(FNote);
  StopNote(FNote2);
  StopNote(FNote3);
  StopNote(FNote4);
  StopNote(FNote5);
  StopNote(FNote6);
end;

procedure TRamugen.EngineCheckPlaying(Sender: TObject);
begin
  if not playing then begin
                        MIDITimer.Enabled := false;
                        exit;
                      end;
end;

procedure TRamugen.EngineLandMarkCheck(Sender: TObject);
begin
  if ChangeLandmark.IsRequired then FLandMark := FNote;
end;

procedure TRamugen.EnginePitch(Sender: TObject);
var zA : Integer;
begin
 if not(BackTrack.IsRequired) then begin
      LastPitch := FNote; //faster with direct access
      LastPitch2 := FNote2;
      LastPitch3 := FNote3;
      LastPitch4 := FNote4;
      LastPitch5 := FNote5;
      LastPitch6 := FNote6;
        //pick a new pitch
      if Pitch.Change.IsRequired then //global jump
         CurrentPitch := pitch.choose
                                 else
         begin //Move (local)
           if MoveInterval.Weighted then
             begin  //Move by interval
               if MoveInterval.MovingUp then
                 CurrentPitch := CurrentPitch + MoveInterval.Choose
                                        else
                 CurrentPitch := CurrentPitch - MoveInterval.Choose;
             end                    else
             begin //Move by local jump
               CurrentPitch := pitch.choose(CurrentPitch - MoveInterval.Max, CurrentPitch + MoveInterval.Max);
             end;
         end;
              //Chord - up to 5 extra notes on top of the main note

     if chordlocal.IsRequired then
       begin  //If chord is made up of intervals, do this:
         FNote2 := FNote + ChordIntervals.Choose;
         while FNote2 > Pitch.Max do
           FNote2 := FNote2 - 12;
         FNote3 := FNote2 + ChordIntervals.Choose;
         while FNote3 > Pitch.Max do
           FNote3 := FNote3 - 12;
         FNote4 := Fnote3 + ChordIntervals.Choose;
         while FNote4 > Pitch.Max do
           FNote4 := FNote4 - 12;
         FNote5 := FNote4 + ChordIntervals.Choose;
         while FNote5 > Pitch.Max do
           FNote5 := FNote5 - 12;
         FNote6 := FNote5 + ChordIntervals.Choose;
         while FNote6 > Pitch.Max do
           FNote6 := FNote6 - 12;
         while FNote2 > Pitch.Min do
           FNote2 := FNote2 + 12;
         while FNote3 > Pitch.Min do
           FNote3 := FNote3 + 12;
         while FNote4 > Pitch.Min do
           FNote4 := FNote4 + 12;
         while FNote5 > Pitch.Min do
           FNote5 := FNote5 + 12;
         while FNote6 > Pitch.Min do
           FNote6 := FNote6 + 12;
       end else //If chord is made up of pitches rather than intervals do this:
       begin
         CurrentPitch2 := pitch.choose;
         CurrentPitch3 := pitch.choose;
         CurrentPitch4 := pitch.choose;
         CurrentPitch5 := pitch.choose;
         CurrentPitch6 := pitch.choose;
       end;
                                   end
                              else
       begin   //swap with last note(s)
         zA := FNote;
         FNote := LastPitch;
         LastPitch := zA;
         zA := FNote2;
         CurrentPitch2 := LastPitch2;  //use the CurrentPitch property to avoid having
                                       //to range-check the values
         LastPitch2 := zA;
         zA := FNote3;
         CurrentPitch3 := LastPitch3;
         LastPitch3 := zA;
         zA := FNote4;
         CurrentPitch4 := LastPitch4;
         LastPitch4 := zA;
         zA := FNote5;
         CurrentPitch5 := LastPitch5;
         LastPitch5 := zA;
         zA := FNote6;
         CurrentPitch6 := LastPitch6;
         LastPitch6 := zA;
      end;
end; //pitch engine

procedure TRamugen.EngineLandMark2(Sender: TObject);
begin
  if ActivateLandmark.IsRequired
    then
      CurrentPitch := FLandMark;
end;

procedure TRamugen.EngineKey(Sender: TObject);
begin
   if TransposeFactor.Change.IsRequired
      then FKey := TransposeFactor.Choose;
   FNote := FNote + FKey;   if FNote > Pitch.Max then FNote := FNote - 12;
   FNote2 := FNote2 + FKey; if FNote2 > Pitch.Max then FNote2 := FNote2 - 12;
   FNote3 := FNote3 + FKey; if FNote3 > Pitch.Max then FNote3 := FNote3 - 12;
   FNote4 := FNote4 + FKey; if FNote4 > Pitch.Max then FNote4 := FNote4 - 12;
   FNote5 := FNote5 + FKey; if FNote5 > Pitch.Max then FNote5 := FNote5 - 12;
   FNote6 := FNote6 + FKey; if FNote6 > Pitch.Max then FNote6 := FNote6 - 12;
end;

procedure TRamugen.EngineAmplitude(Sender: TObject);
begin
 if Amplitude.Change.IsRequired then
                 CurrentAmplitude := amplitude.choose
                                else
                 begin  //Cresc./Dim.
                   if Amplitude.MovingUp
                     then CurrentAmplitude := CurrentAmplitude + Amplitude.UnitSize
                     else CurrentAmplitude := CurrentAmplitude - Amplitude.UnitSize
                 end;
end;

procedure TRamugen.EngineDuration(Sender: TObject);
begin
 if Duration.Change.IsRequired then
                 CurrentDuration := duration.choose
                               else begin
                     if Duration.MovingUp then
                 CurrentDuration := CurrentDuration + Duration.UnitSize
                                                else
                 CurrentDuration := CurrentDuration - Duration.UnitSize
                                     end;
end;

procedure TRamugen.EngineStartNote(Sender: TObject);
var zA : Integer;
begin
 zA := CurrentAmplitude; if Rest.IsRequired then zA := 0;
 StartNote(FNote, zA);
 if NumNotes.Choose > 1 then StartNote(FNote2, zA);
  if NumNotes.Choose > 2 then StartNote(FNote3, zA);
  if NumNotes.Choose > 3 then StartNote(FNote4, zA);
  if NumNotes.Choose > 4 then StartNote(FNote5, zA);
  if NumNotes.Choose > 5 then StartNote(FNote6, zA);
 MIDITimer.Interval := CurrentDuration;
end;








end.