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.