TRAMUGENCLASS.PAS
{
**************************************************************
TRamugenClass unit
**************************************************************
Contains the following classes:
TRamugenPreset : Preset containing hard limits and probabilities which
control how random values are selected;
TRamugenMood and TRamugenMindset : Two very similar objects which just
select presets and moods, respectively; they're used for
the default A.I. and are present in the TCustRamugen class
because they're useful features to have in any similar project.
TCustRamugen : The bare bones of TRamugen, ie. without the engine.
This is the class you should inherit from if you're making
object-oriented music applications with the TRamugen component
and wish to subclass in order to extend functionality.
TRamugen : The actual component which is registered in Delphi. If you're not
using Ramugen as a Delphi component but still wish to use it, just
add it to your interface 'uses' clause and call TRamugen.Create(Self)
to instantiate it. It's a singleton class and lives as long as your
application so there's no unhandled clean-up to do.
This unit uses objects in TRamugenSmallClasses and TMinMax. The dialog-box provided
with the TWeightingSystem object for its 'InputWeightings' method is in unit WSDialog.
TRamugenSmallClasses includes TMidiArray, TGlobalProbability and TWeightingSystem.
If you do write your own music apps with the components, please drop me a line
because I'd most definitely be interested in learning about your approach to music-making.
mailto : gregskius@_NOSPAMTHANKYOU_tesco.net
**************************************************************
Copyright 2007 OPEN SOURCE Greg Fox
http://homepages.tesco.net/gregskius/ramugen.html
**************************************************************
}
unit TRamugenClass;
interface
uses Dialogs, WinTypes, Classes, SysUtils, Controls, StdCtrls, ExtCtrls,
WSDialog, TMinMaxClass, TSmallRamugenClasses;
type
TRamugenPreset = class(TComponent)
protected
FName : string[32];
FNumNotes,
FDuration,
FAmplitude,
FArticulation,
FAggregateDelay : TSimpleMinMax; //see separate unit TMinMax
FTransposeFactor,
FPitch,
FMoveInterval,
FChordIntervals : TExtendedMinMax;
FMoveHand,
FChangeLandmark,
FActivateLandmark,
FBackTrack,
FRest,
FChordLocal : TGlobalProbability; //from TSmallRamugenClasses
FFilled : Boolean;
procedure SetPName (T: string);
function GetPName : String;
public
procedure Mu;
procedure Assign(aPreset : TPersistent); override;
procedure AssignTo(aPreset : TPersistent); override;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
published
property PresetName : string read GetPName write SetPName;
property IsFilled : Boolean read FFilled write FFilled;
property Duration : TSimpleMinMax read FDuration write FDuration;
property Amplitude : TSimpleMinMax read FAmplitude write FAmplitude;
property Articulation : TSimpleMinMax read FArticulation write FArticulation;
property AggregateDelay : TSimpleMinMax read FAggregateDelay write FAggregateDelay;
property NumNotes : TSimpleMinMax read FNumNotes write FNumNotes;
property TransposeFactor : TExtendedMinMax read FTransposeFactor write FTransposeFactor;
property Pitch : TExtendedMinMax read FPitch write FPitch;
property MoveInterval : TExtendedMinMax read FMoveInterval write FMoveInterval;
property ChordIntervals : TExtendedMinMax read FChordIntervals write FChordIntervals;
property MoveHand : TGlobalProbability read FMoveHand write FMoveHand;
property ChangeLandmark : TGlobalProbability read FChangeLandmark write FChangeLandmark;
property ActivateLandmark : TGlobalProbability read FActivateLandmark write FActivateLandmark;
property Backtrack : TGlobalProbability read FBacktrack write FBacktrack;
property Rest : TGlobalProbability read FRest write FRest;
property ChordLocal : TGlobalProbability read FChordLocal write FChordLocal;
end;
TRamugenMood = class(TWeightingSystem)
protected
FFilled : Boolean; //not worth superclassing for one property
public
PresetChange : TGlobalProbability;
procedure Assign(X : TPersistent); override;
procedure AssignTo(X : TPersistent); override;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
published
property IsFilled : Boolean read FFilled write FFilled;
end;
TRamugenMindset = class(TWeightingSystem)
protected
FFilled : Boolean;
public
MoodChange : TGlobalProbability;
procedure Assign(X : TPersistent); override;
procedure AssignTo(X : TPersistent); override;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
published
property IsFilled : Boolean read FFilled write FFilled;
end;
//Main Custom Ramugen Class
TDevolvee = (dvPresets, dvMoods, dvMindsets);
TDevolvees = set of TDevolvee;
TCrescendo = (crescendo, diminuendo);
TAccelerando = (accelerando, rallentando);
TCustRamugen = class(TComponent)
private
protected
FMIDIDevice : Integer;
FMIDIVoice : Integer;
FMIDIChannel : Integer;
MidiHandle : Integer;
FMIDIArray : TMidiArray;
FStoreToArray : Boolean;
FSkipEngine : Boolean;
FNote,
FNote2,
FNote3,
FNote4,
FNote5,
FNote6,
FOldNote,
FOldNote2,
FOldNote3,
FOldNote4,
FOldNote5,
FOldNote6,
FDuration,
FAmplitude,
FKey,
FLandmark : Integer;
APreset : TRamugenPreset;
AName : string;
ADuration,
AAmplitude,
AArticulation,
AAggregateDelay,
ANumNotes : TSimpleMinMax;
ATransposeFactor,
APitch,
AMoveInterval,
AChordIntervals : TExtendedMinMax;
AMoveHand,
AChangeLandmark,
AActivateLandmark,
ABackTrack,
ARest,
AChordLocal : TGlobalProbability;
AMood : TRamugenMood;
AMindset : TRamugenMindset;
APresetChange,
AMoodChange,
AMindsetChange : TGlobalprobability;
FActivePreset,
FActiveMood,
FActiveMindset : Integer;
FDevolvees : TDevolvees;
Presets : Array [0..127] of TRamugenPreset;
Moods : Array [0..127] of TRamugenMood;
Mindsets : Array [0..127] of TRamugenMindset;
FCrescendo : TCrescendo;
FAccelerando : TAccelerando;
//events
FOnMemoryPhraseStart : TNotifyEvent;
FOnMemoryPhraseEnd : TNotifyEvent;
FOnPlayNoteEnd : TNotifyEvent;
FOnNoteStart : TNoteStartEvent;
procedure SetDefaults; virtual;
function SetNoteSub(T : Integer) : Integer; //does the donkeywork for the next six
procedure SetNote(T : Integer);
procedure SetNote2(T : Integer);
procedure SetNote3(T : Integer);
procedure SetNote4(T : Integer);
procedure SetNote5(T : Integer);
procedure SetNote6(T : Integer);
procedure SetAmplitude(T : Integer);
procedure SetDuration(T : Integer);
procedure SetMIDIDevice(T : Integer); virtual;
procedure SetMIDIVoice(T : Integer);
procedure SetMIDIChannel(T : Integer);
procedure SetActivePreset(T : Integer);
procedure SetPresetName(T : String);
procedure SetActiveMood(T : Integer);
procedure SetActiveMindset(T : Integer);
procedure SetPFilled (T : Boolean);
procedure SetMFilled (T : Boolean);
procedure SetSFilled (T : Boolean);
procedure SetMemoryPhraseStartEvent (X : TNotifyEvent); //event setters
procedure SetMemoryPhraseEndEvent (X : TNotifyEvent);
procedure SetNoteStart (X : TNoteStartEvent);
procedure SetPlayNoteEnd(X : TNotifyEvent);
procedure SetPreset(P : Integer; Value : TRamugenPreset);
{
The following block defines the recommended interface for
specific engine implementations for Ramugen type objects.
BrainTimerDefault is the suggested default event-handler
for a timer to control mindset/mood/preset-selection.
MIDITimerDefault is the suggested default event-handler
for a timer to control the main note-playing engine.
I recommend that you break this main engine down into sub-methods
using the "Template Method" Pattern. The recommended steps are provided.
The published object TRamugen (a TCustRamugen descendant) implements
this interface.
}
procedure BrainTimerDefault(Sender: TObject); virtual; abstract;//mood-changer
procedure MIDITimerDefault(Sender: TObject); virtual; abstract; //main engine
//main engine is a template method containing the following sub-methods:
procedure EngineInitialise(Sender: TObject); virtual; abstract;
procedure EngineStopNote(Sender: TObject); virtual; abstract;
procedure EngineCheckPlaying(Sender: TObject); virtual; abstract;
procedure EngineLandMarkCheck(Sender: TObject); virtual; abstract;
procedure EnginePitch(Sender: TObject); virtual; abstract;
procedure EngineLandMark2(Sender: TObject); virtual; abstract;
procedure EngineKey(Sender: TObject); virtual; abstract;
procedure EngineAmplitude(Sender: TObject); virtual; abstract;
procedure EngineDuration(Sender: TObject); virtual; abstract;
procedure EngineRest(Sender: TObject); virtual; abstract;
procedure EngineStartNote(Sender: TObject); virtual; abstract;
procedure EngineFinalise(Sender: TObject); virtual; abstract;
procedure Start; virtual; abstract; //basic start and stop functionality
procedure Stop; virtual; abstract;
//some Getters
function GetPFilled : Boolean;
function GetMFilled : Boolean;
function GetSFilled : Boolean;
function GetPresetCount : Integer;
function GetMoodCount : Integer;
function GetMindsetCount : Integer;
function GetPreset(P : Integer) : TRamugenPreset;
public
procedure SaveToFile(FileName : string = 'prompt'); virtual; abstract;
procedure SaveToStream(SourceStream : TStream); virtual; abstract;
procedure LoadFromFile(FileName : string = 'prompt'); virtual; abstract;
procedure LoadFromStream(SourceStream : TStream); virtual; abstract;
procedure SaveMemoryToFile(FileName : string = 'prompt'); virtual;
procedure LoadMemoryFromFile(FileName : string = 'prompt'; Append : boolean = false); virtual;
procedure PresetClone(PresetNumber : Integer);
//MIDI-handling methods : see TMIDIArray (these are just an interface to hide the worker object from end-users)
procedure StartNote(pitch, amplitude : Integer); overload; virtual;
procedure StartNote(notename : string; octave : Integer = 5; dynamicmarking : string = 'mf'); overload; virtual;
procedure StopNote(pitch : Integer); overload; virtual;
procedure StopNote(notename : string; octave : Integer = 5); overload; virtual;
procedure PlayNote(pitch : Integer; duration : Integer=700; amplitude : Integer=100); overload; virtual;
procedure PlayNote(notename : string; octave : Integer = 5; duration : Integer = 700; dynamicmarking : string = 'mf'); overload; virtual;
procedure PlayArray(pitches : array of integer; duration : Integer = 700; amplitude : Integer = 100; TranspositionFactor : Integer = 0; SpeedPercent : Integer = 100); overload; virtual;
procedure PlayArray(pitches : array of integer; durations : array of integer; amplitude : Integer = 100; TranspositionFactor : Integer = 0; SpeedPercent : Integer = 100); overload; virtual;
procedure PlayArray(pitches : array of integer; durations : array of integer; amplitudes : array of integer; TranspositionFactor : Integer = 0; SpeedPercent : Integer = 100; AmplitudeLowerLimit : Integer = 40; AmplitudeHigherLimit : Integer = 127); overload; virtual;
procedure PlayPhrase(transpositionfactor : integer = 0; speedpercent : integer = 100); virtual; //play using data already loaded
procedure ClearMemory; virtual;
procedure AddNote(pitch : integer; duration : integer = 700; amplitude : integer = 100); virtual;
procedure SetMoodWeightings; virtual;
procedure SetMindsetWeightings; virtual;
procedure Assign(X : TPersistent); override;
procedure AssignTo(X : TPersistent); override;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
//run-time properties
property CurrentPitch : Integer read FNote write SetNote;
property CurrentPitch2 : Integer read FNote2 write SetNote2;
property CurrentPitch3 : Integer read FNote3 write SetNote3;
property CurrentPitch4 : Integer read FNote4 write SetNote4;
property CurrentPitch5 : Integer read FNote5 write SetNote5;
property CurrentPitch6 : Integer read FNote6 write SetNote6;
property LastPitch : Integer read FOldNote write FOldNote;
property LastPitch2 : Integer read FOldNote2 write FOldNote2;
property LastPitch3 : Integer read FOldNote3 write FOldNote3;
property LastPitch4 : Integer read FOldNote4 write FOldNote4;
property LastPitch5 : Integer read FOldNote5 write FOldNote5;
property LastPitch6 : Integer read FOldNote6 write FOldNote6;
property CurrentAmplitude : Integer read FAmplitude write SetAmplitude;
property CurrentDuration : Integer read FDuration write SetDuration;
property CurrentDynamicDirection : TCrescendo read FCrescendo write FCrescendo;
property CurrentSpeedDirection : TAccelerando read FAccelerando write FAccelerando;
property PresetCount : Integer read GetPresetCount;
property MoodCount : Integer read GetMoodCount;
property MindsetCount : Integer read GetMindsetCount;
property DataPresets[P : Integer]: TRamugenPreset read GetPreset write SetPreset;
property PresetName : string read AName write SetPresetName;
property ActivePresetFilled : Boolean read GetPFilled write SetPFilled;
property ActiveMoodFilled : Boolean read GetMFilled write SetMFilled;
property ActiveMindsetFilled : Boolean read GetSFilled write SetSFilled;
published
//events
property OnNoteStart : TNoteStartEvent read FOnNoteStart write SetNoteStart;
property OnNoteStop : TNotifyEvent read FOnPlayNoteEnd write SetPlayNoteEnd;
property OnMemoryPhraseStop : TNotifyEvent read FOnMemoryPhraseEnd write SetMemoryPhraseEndEvent;
property OnMemoryPhraseStart : TNotifyEvent read FOnMemoryPhraseStart write SetMemoryPhraseStartEvent;
property Devolvees : TDevolvees read FDevolvees write FDevolvees;
//the following inset are an interface to the initial preset object
property Memory : TMidiArray read FMidiArray write FMidiArray;
property Pitch : TExtendedMinMax read APitch write APitch;
property TransposeFactor : TExtendedMinMax read ATransposeFactor write ATransposeFactor;
property MoveInterval : TExtendedMinMax read AMoveInterval write AMoveInterval;
property ChordIntervals : TExtendedMinMax read AChordIntervals write AChordIntervals;
property Duration : TSimpleMinMax read ADuration write ADuration;
property AggregateDelay : TSimpleMinMax read AAggregateDelay write AAggregateDelay;
property Articulation : TSimpleMinMax read AArticulation write AArticulation;
property Amplitude : TSimpleMinMax read AAmplitude write AAmplitude;
property NumNotes : TSimpleMinMax read ANumNotes write ANumNotes;
property MoveHand : TGlobalProbability read AMoveHand write AMoveHand;
property ActivateLandmark : TGlobalProbability read AActivateLandmark write AActivateLandmark;
property ChangeLandmark : TGlobalProbability read AChangeLandmark write AChangeLandmark;
property BackTrack : TGlobalProbability read ABackTrack write ABackTrack;
property Rest : TGlobalProbability read ARest write ARest;
property ChordLocal : TGlobalProbability read AChordLocal write AChordLocal;
property ActivePreset : Integer read FActivePreset write SetActivePreset;
property ActiveMood : Integer read FActiveMood write SetActiveMood;
property ActiveMindset : Integer read FActiveMindset write SetActiveMindset;
property PresetChange : TGlobalProbability read APresetChange write APresetChange;
property MoodChange : TGlobalProbability read AMoodChange write AMoodChange;
property MindsetChange : TGlobalProbability read AMindsetChange write AMindsetChange;
property MIDIDevice : Integer read FMIDIDevice write SetMIDIDevice;
property MIDIVoice : Integer read FMIDIVoice write SetMIDIVoice;
property MIDIChannel : Integer read FMIDIChannel write SetMIDIChannel;
property RecordOnly : Boolean read FSkipEngine write FSkipEngine;
property StorePlayback : Boolean read FStoreToArray write FStoreToArray;
end;
TRamugen = class(TCustRamugen)
protected
FPlaying : Boolean;
MIDITimer,
BrainTimer : TTimer;
FMIDIOnTimer,
FBrainOnTimer : TNotifyEvent;
FOnStart : TNotifyEvent;
FOnStop : TNotifyEvent;
//placeholders allowing over-riding of main engine sub-methods
FEngineInitialise,
FEngineStopNote,
FEngineCheckPlaying,
FEngineLandMarkCheck,
FEnginePitch,
FEngineLandMark2,
FEngineKey,
FEngineAmplitude,
FEngineDuration,
FEngineRest,
FEngineStartNote,
FEngineFinalise : TNotifyEvent;
//setters
procedure SetMainEngine (X : TNotifyEvent);
procedure SetBrainEngine (X : TNotifyEvent);
procedure SetPlaying (T : Boolean); virtual;
procedure SetStartPlaying(X : TNotifyEvent);
procedure SetStopPlaying(X : TNotifyEvent);
procedure SetBrainInterval(T: Integer);
procedure MIDITimerDefault(Sender: TObject); override; //main engine
procedure BrainTimerDefault(Sender: TObject); override; //mood-changer
//main engine is a template method containing the following sub-methods:
procedure EngineStopNote(Sender: TObject); override;
procedure EngineCheckPlaying(Sender: TObject); override;
procedure EngineLandMarkCheck(Sender: TObject); override;
procedure EnginePitch(Sender: TObject); override;
procedure EngineLandMark2(Sender: TObject); override;
procedure EngineKey(Sender: TObject); override;
procedure EngineAmplitude(Sender: TObject); override;
procedure EngineDuration(Sender: TObject); override;
procedure EngineStartNote(Sender: TObject); override;
function GetBrainInterval : Integer;
public
procedure SaveToStream(SourceStream : TStream); override;
procedure SaveToFile(FileName : string = 'prompt'); override;
procedure LoadFromFile(FileName : string = 'prompt'); override;
procedure LoadFromStream(SourceStream : TStream); override;
procedure Mu;
procedure Start; override;
procedure Stop; override;
procedure Assign(X : TPersistent); override;
procedure AssignTo(X : TPersistent); override;
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
//run-time properties
property Playing : Boolean read FPlaying write SetPlaying;
published
//events
property OnEngineStart : TNotifyEvent read FOnStart write SetStartPlaying;
property OnEngineStop : TNotifyEvent read FOnStop write SetStopPlaying;
//wholesale override of Ramugen engine (ie. exposes the two Timers basically!)
property TEO_01_PlayNote : TNotifyEvent read FMIDIOnTimer write SetMainEngine; //nb. TEO rather than MEO so that the OnEvents are at the top in the object inspector!
property TEO_02_Moods : TNotifyEvent read FBrainOnTimer write SetBrainEngine;
//partial override of engine - keep some bits, change others (Template Method)
property PEO_01_Initialise : TNotifyEvent read FEngineInitialise write FEngineInitialise;
property PEO_02_StopNotes : TNotifyEvent read FEngineStopNote write FEngineStopNote;
property PEO_03_CheckPlaying : TNotifyEvent read FEngineCheckPlaying write FEngineCheckPlaying;
property PEO_04_UpdateLandMark : TNotifyEvent read FEngineLandMarkCheck write FEngineLandMarkCheck;
property PEO_05_PITCH : TNotifyEvent read FEnginePitch write FEnginePitch;
property PEO_06_Decide_LandMark : TNotifyEvent read FEngineLandMark2 write FEngineLandMark2;
property PEO_07_KEY : TNotifyEvent read FEngineKey write FEngineKey;
property PEO_08_AMPLITUDE : TNotifyEvent read FEngineAmplitude write FEngineAmplitude;
property PEO_09_DURATION : TNotifyEvent read FEngineDuration write FEngineDuration;
property PEO_10_Decide_REST : TNotifyEvent read FEngineRest write FEngineRest;
property PEO_11_StartNotes : TNotifyEvent read FEngineStartNote write FEngineStartNote;
property PEO_12_Finalise : TNotifyEvent read FEngineFinalise write FEngineFinalise;
//design-time properties
property BrainInterval : Integer read GetBrainInterval write SetBrainInterval;
end;
Procedure Register;
implementation
uses MMSystem;
// Constructor & Destructor Pairs
constructor TRamugenMindset.Create;
begin
inherited;
MoodChange := TGlobalProbability.Create;
end;
destructor TRamugenMindset.Destroy;
begin
FreeAndNil(MoodChange);
inherited;
end;
constructor TRamugenMood.Create;
begin
inherited;
PresetChange := TGlobalProbability.Create;
end;
destructor TRamugenMood.Destroy;
begin
FreeAndNil(PresetChange);
inherited;
end;
constructor TCustRamugen.Create(AOwner: TComponent);
var t: Integer;
begin
inherited Create(AOwner);
randomize;
for t := 0 to 127 do Presets[t] := TRamugenPreset.Create(nil);
for t := 0 to 127 do Moods[t] := TRamugenMood.Create(nil);
for t := 0 to 127 do Mindsets[t] := TRamugenMindset.Create(nil);
FMIDIArray := TMidiArray.Create(nil);
FSkipEngine := false;
ActivePreset := 0; //nb. preset-adapter pointers are set by the setter
ActiveMood := 0;
ActiveMindset := 0;
SetDefaults; //Default property settings
end;
destructor TCustRamugen.Destroy;
var t: Integer;
begin
MidiOutClose(midihandle);
for t := 0 to 127 do FreeAndNil(Presets[t]);
for t := 0 to 127 do FreeAndNil(Moods[t]);
for t := 0 to 127 do FreeAndNil(Mindsets[t]);
FreeAndNil(FMIDIArray);
inherited;
end;
constructor TRamugen.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
MidiDevice := 0;
MIDITimer := TTimer.Create(nil);
MIDITimer.Enabled := false;
MIDITimer.OnTimer := MIDITimerDefault;
BrainTimer := TTimer.Create(nil);
BrainTimer.Enabled := false;
BrainTimer.OnTimer := BrainTimerDefault;
FEngineStopNote := EngineStopNote; //nb. initialise, rest and finalise remain abstract but can be user-assigned
FEngineCheckPlaying := EngineCheckPlaying;
FEngineLandMarkCheck := EngineLandMarkCheck;
FEnginePitch := EnginePitch;
FEngineLandMark2 := EngineLandMark2;
FEngineKey := EngineKey;
FEngineAmplitude := EngineAmplitude;
FEngineDuration := EngineDuration;
FEngineStartNote := EngineStartNote;
end;
destructor TRamugen.Destroy;
begin
FreeAndNil(MIDITimer);
FreeAndNil(BrainTimer);
inherited;
end;
constructor TRamugenPreset.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
FPitch := TExtendedMinMax.Create;
FDuration := TSimpleMinMax.Create;
FDuration.HardMax := 30000;
FAmplitude := TSimpleMinMax.Create;
FArticulation := TSimpleMinMax.Create;
FAggregateDelay := TSimpleMinMax.Create;
FTransposeFactor := TExtendedMinMax.Create;
FTransposeFactor.HardMax := 30;
FTransposeFactor.Weightings.Initialize (0);
FMoveHand := TGlobalProbability.Create;
FChangeLandmark := TGlobalProbability.Create;
FActivateLandmark := TGlobalProbability.Create;
FBackTrack := TGlobalProbability.Create;
FRest := TGlobalProbability.Create;
FChordLocal := TGlobalProbability.Create;
FNumNotes := TSimpleMinMax.Create;
FMoveInterval := TExtendedMinMax.Create;
FMoveInterval.HardMax := 24;
FMoveInterval.Weightings.Initialize (0);
FChordIntervals := TExtendedMinMax.Create;
FChordIntervals.HardMax := 40;
FChordIntervals.Weightings.Initialize (0);
FChordIntervals.HardMax := 12;
FChordIntervals.Weightings.Initialize (1);
end;
destructor TRamugenPreset.Destroy;
begin
FreeAndNil(FPitch);
FreeAndNil(FDuration);
FreeAndNil(FAmplitude);
FreeAndNil(FArticulation);
FreeAndNil(FAggregateDelay);
FreeAndNil(FTransposeFactor);
FreeAndNil(FMoveHand);
FreeAndNil(FChangeLandmark);
FreeAndNil(FActivateLandmark);
FreeAndNil(FBackTrack);
FreeAndNil(FRest);
FreeAndNil(FChordLocal);
FreeAndNil(FNumNotes);
FreeAndNil(FMoveInterval);
FreeAndNil(FChordIntervals);
inherited;
end;
//Save and Load methods
procedure TCustRamugen.SaveMemoryToFile(FileName : string = 'prompt'); //delegate
begin
Memory.SaveToFile(FileName);
end;
procedure TCustRamugen.LoadMemoryFromFile(FileName : string = 'prompt'; Append : Boolean = false);
begin
Memory.LoadFromFile(FileName,Append);
end;
procedure TRamugen.SaveToFile(FileName : string = 'prompt');
var
str1 : TFileStream;
savedialog1 : TSaveDialog;
t : Integer;
begin
if FileExists(FileName) then
if MessageDlg('Do you want to over-write this file?',mtConfirmation,[MbYes, MbNo],0) = mrNo
then FileName := 'prompt';
if (comparestr(FileName, 'prompt') = 0) then
begin
savedialog1 := TSaveDialog.Create(nil);
try
savedialog1.Filter:='Ramugen Settings|*.rmg';
savedialog1.DefaultExt := 'rmg';
savedialog1.Options := [ofOverwritePrompt];
if savedialog1.execute then FileName := savedialog1.filename;
finally
savedialog1.free;
end;
end;
str1 := TFileStream.Create(FileName, fmOpenWrite or fmCreate);
try
str1.Seek(0,soFromBeginning);
for t := 0 to 127 do
begin
str1.WriteComponent(Presets[t]);
str1.WriteComponent(Moods[t]);
str1.WriteComponent(Mindsets[t]);
end;
finally
str1.free;
end;
end;
procedure TRamugen.LoadFromFile(FileName : string = 'prompt');
var
str1 : TFileStream;
opendialog1 : TOpenDialog;
t : Integer;
begin
if CompareStr(Filename, 'prompt') = 0 then
begin
opendialog1 := TOpenDialog.Create(nil);
try
opendialog1.Options := [ofFileMustExist];
opendialog1.filter:='Ramugen Settings File|*.rmg';
if opendialog1.execute then Filename := opendialog1.filename;
finally
opendialog1.Free;
end;
end;
if (fileexists(filename)) then
begin
str1 := TFileStream.Create(FileName, fmOpenRead);
try
str1.Seek(0,soFromBeginning);
for t := 0 to 127 do
begin
Presets[t] := str1.readcomponent(Presets[t]) as TRamugenPreset;
Moods[t] := str1.readcomponent(Moods[t]) as TRamugenMood;
Mindsets[t] := str1.readcomponent(Mindsets[t]) as TRamugenMindset;
end;
finally
str1.free;
end;
end;
end;
procedure TRamugen.LoadFromStream(SourceStream : TStream);
var t : Integer;
begin
SourceStream.Seek(0,soFromBeginning);
for t := 0 to 127 do
begin
Presets[t] := SourceStream.readcomponent(Presets[t]) as TRamugenPreset;
Moods[t] := SourceStream.readcomponent(Moods[t]) as TRamugenMood;
Mindsets[t] := SourceStream.readcomponent(Mindsets[t]) as TRamugenMindset;
end;
end;
procedure TRamugen.SaveToStream(SourceStream : TStream);
var t : Integer;
begin
sourcestream.Seek(0,soFromBeginning);
for t := 0 to 127 do
begin
sourcestream.WriteComponent(Presets[t]);
sourcestream.WriteComponent(Moods[t]);
sourcestream.WriteComponent(Mindsets[t]);
end;
end;
procedure TCustRamugen.PresetClone(PresetNumber : Integer);
begin
If PresetNumber > (PresetCount - 1) then exit;
APreset.Assign(Presets[PresetNumber]);
end;
// Mu methods
procedure TRamugen.Mu;
var x : Integer;
begin
for x := 0 to 127 do begin
ActivePreset := x;
APreset.Backtrack.Probability := random(1);
APreset.Rest.Probability := random(1);
APreset.Mu;
end;
for x := 0 to 127 do begin
ActiveMood := x;
AMood.Mu;
end;
for x := 0 to 127 do begin
ActiveMindset := x;
AMindset.Mu;
end;
end;
procedure TRamugenPreset.Mu;
begin
Pitch.HardMin := 26; Pitch.HardMax := 104;
Pitch.SetRange(Pitch.Choose, Pitch.Choose);
Pitch.Mu;
Duration.HardMin := 50; Duration.HardMax := 4500;
Duration.Min := 50; Duration.Max := 4500;
Duration.SetRange(Duration.Choose, Duration.Choose);
Amplitude.HardMin := 45; Amplitude.HardMax := 127;
Amplitude.SetRange(Amplitude.Choose, Amplitude.Choose);
NumNotes.SetRange(1,3);
end;
//Assign methods
procedure TRamugenPreset.Assign(aPreset : TPersistent);
begin
if aPreset is TRamugenPreset then begin
PresetName := TRamugenPreset(aPreset).PresetName;
ChordLocal.Assign(TRamugenPreset(aPreset).ChordLocal);
Rest.Assign(TRamugenPreset(aPreset).Rest);
BackTrack.Assign(TRamugenPreset(aPreset).BackTrack);
ActivateLandmark.Assign(TRamugenPreset(aPreset).ActivateLandmark);
ChangeLandmark.Assign(TRamugenPreset(aPreset).ChangeLandmark);
MoveHand.Assign(TRamugenPreset(aPreset).MoveHand);
ChordIntervals.Assign(TRamugenPreset(aPreset).ChordIntervals);
MoveInterval.Assign(TRamugenPreset(aPreset).MoveInterval);
Pitch.Assign(TRamugenPreset(aPreset).Pitch);
TransposeFactor.Assign(TRamugenPreset(aPreset).TransposeFactor);
NumNotes.Assign(TRamugenPreset(aPreset).NumNotes);
AggregateDelay.Assign(TRamugenPreset(aPreset).AggregateDelay);
Articulation.Assign(TRamugenPreset(aPreset).Articulation);
Amplitude.Assign(TRamugenPreset(aPreset).Amplitude);
Duration.Assign(TRamugenPreset(aPreset).Duration);
IsFilled := true;
end
else
inherited Assign(aPreset);
end;
procedure TRamugenPreset.AssignTo(aPreset : TPersistent);
begin
if aPreset is TRamugenPreset then begin
TRamugenPreset(aPreset).PresetName := PresetName;
ChordLocal.AssignTo(TRamugenPreset(aPreset).ChordLocal);
Rest.AssignTo(TRamugenPreset(aPreset).Rest);
BackTrack.AssignTo(TRamugenPreset(aPreset).BackTrack);
ActivateLandmark.AssignTo(TRamugenPreset(aPreset).ActivateLandmark);
ChangeLandmark.AssignTo(TRamugenPreset(aPreset).ChangeLandmark);
MoveHand.AssignTo(TRamugenPreset(aPreset).MoveHand);
ChordIntervals.AssignTo(TRamugenPreset(aPreset).ChordIntervals);
MoveInterval.AssignTo(TRamugenPreset(aPreset).MoveInterval);
Pitch.AssignTo(TRamugenPreset(aPreset).Pitch);
TransposeFactor.AssignTo(TRamugenPreset(aPreset).TransposeFactor);
NumNotes.AssignTo(TRamugenPreset(aPreset).NumNotes);
AggregateDelay.AssignTo(TRamugenPreset(aPreset).AggregateDelay);
Articulation.AssignTo(TRamugenPreset(aPreset).Articulation);
Amplitude.AssignTo(TRamugenPreset(aPreset).Amplitude);
Duration.AssignTo(TRamugenPreset(aPreset).Duration);
TRamugenPreset(aPreset).IsFilled := true;
end
else
inherited AssignTo(aPreset);
end;
procedure TRamugen.Assign(X: TPersistent);
begin
inherited Assign(X); //TCustRamugen.Assign
if X is TRamugen then
begin
Playing := TRamugen(X).Playing;
MIDITimer.Interval := TRamugen(X).MIDITimer.Interval;
BrainTimer.Interval := TRamugen(X).BrainTimer.Interval;
end;
end;
procedure TRamugen.AssignTo(X: TPersistent);
begin
inherited AssignTo(X); //TCustRamugen.AssignTo
if X is TRamugen then
begin
TRamugen(X).Playing := Playing;
TRamugen(X).MIDITimer.Interval := MIDITimer.Interval;
TRamugen(X).BrainTimer.Interval := BrainTimer.Interval;
end;
end;
procedure TCustRamugen.Assign(X: TPersistent);
var t : Integer;
begin
if X is TCustRamugen then
begin
FLandmark := TCustRamugen(X).FLandmark;
FMIDIArray.Assign(TCustRamugen(X).FMIDIArray);
MIDIDevice := TCustRamugen(X).MIDIDevice;
MIDIVoice := TCustRamugen(X).MIDIVoice;
MIDIChannel := TCustRamugen(X).MIDIChannel;
FOnNoteStart := TCustRamugen(X).FOnNoteStart;
FOnPlayNoteEnd := TCustRamugen(X).FOnPlayNoteEnd;
FOnMemoryPhraseStart := TCustRamugen(X).FOnMemoryPhraseStart;
FOnMemoryPhraseEnd := TCustRamugen(X).FOnMemoryPhraseEnd;
FCrescendo := TCustRamugen(X).FCrescendo;
FAccelerando := TCustRamugen(X).FAccelerando;
for t := 0 to 127 do
begin
Presets[t].Assign(TCustRamugen(X).Presets[t]);
Moods[t].Assign(TCustRamugen(X).Moods[t]);
Mindsets[t].Assign(TCustRamugen(X).Mindsets[t]);
end;
FDevolvees := TCustRamugen(X).FDevolvees;
ActiveMindset := TCustRamugen(X).ActiveMindset;
ActiveMood := TCustRamugen(X).ActiveMood;
ActivePreset := TCustRamugen(X).ActivePreset; //no need to do the A-type pointers
end else
inherited Assign(X);
end;
procedure TCustRamugen.AssignTo(X: TPersistent);
var t : Integer;
begin
if X is TCustRamugen then
begin
TCustRamugen(X).FLandmark := FLandmark;
FMIDIArray.AssignTo(TCustRamugen(X).FMIDIArray);
TCustRamugen(X).MIDIDevice := MIDIDevice;
TCustRamugen(X).MIDIVoice := MIDIVoice;
TCustRamugen(X).MIDIChannel := MIDIChannel;
TCustRamugen(X).FCrescendo := FCrescendo;
TCustRamugen(X).FAccelerando := FAccelerando;
for t := 0 to 127 do
begin
Presets[t].AssignTo(TCustRamugen(X).Presets[t]);
Moods[t].AssignTo(TCustRamugen(X).Moods[t]);
Mindsets[t].AssignTo(TCustRamugen(X).Mindsets[t]);
end;
TCustRamugen(X).FDevolvees := FDevolvees;
TCustRamugen(X).ActiveMindset := ActiveMindset;
TCustRamugen(X).ActiveMood := ActiveMood;
TCustRamugen(X).ActivePreset := ActivePreset; //no need to do the A-type pointers
end else
inherited Assign(X);
end;
procedure TRamugenMood.Assign(X: TPersistent);
begin
if X is TRamugenMood then
begin
FFilled := TRamugenMood(X).FFilled;
PresetChange.Assign(TRamugenMood(X).PresetChange);
end else inherited Assign(X);
end;
procedure TRamugenMood.AssignTo(X: TPersistent);
begin
if X is TRamugenMood then
begin
TRamugenMood(X).FFilled := FFilled;
PresetChange.AssignTo(TRamugenMood(X).PresetChange);
end else inherited AssignTo(X);
end;
procedure TRamugenMindset.Assign(X: TPersistent);
begin
if X is TRamugenMindset then
begin
FFilled := TRamugenMindset(X).FFilled;
MoodChange.Assign(TRamugenMindset(X).MoodChange);
end else inherited Assign(X);
end;
procedure TRamugenMindset.AssignTo(X: TPersistent);
begin
if X is TRamugenMindset then
begin
TRamugenMindset(X).FFilled := FFilled;
MoodChange.AssignTo(TRamugenMindset(X).MoodChange);
end else inherited AssignTo(X);
end;
// Delegation Setters
procedure TCustRamugen.SetNoteStart(X : TNoteStartEvent);
begin
FOnNoteStart := X;
Memory.OnNoteStart := X; //automatically mirror the event in the worker object
end;
procedure TCustRamugen.SetPlayNoteEnd(X : TNotifyEvent);
begin
FOnPlayNoteEnd := X;
Memory.OnNoteStop := X;
end;
procedure TCustRamugen.SetMemoryPhraseStartEvent (X : TNotifyEvent);
begin
FOnMemoryPhraseStart := X;
Memory.OnPhraseStart := X;
end;
procedure TCustRamugen.SetMemoryPhraseEndEvent (X : TNotifyEvent);
begin
FOnMemoryPhraseEnd := X;
Memory.OnPhraseStop := X;
end;
procedure TRamugen.SetMainEngine(X : TNotifyEvent);
begin
FMIDIOnTimer := X; //just stores it for the object inspector
MIDITimer.OnTimer := X; //delegate to hidden worker object thus hiding its default handler
end;
procedure TRamugen.SetBrainEngine(X : TNotifyEvent);
begin
FBrainOnTimer := X;
BrainTimer.OnTimer := X;
end;
procedure TCustRamugen.SetActivePreset(T : Integer);
begin
if T < 0 then T := 0;
if T > 127 then T := 127;
FActivePreset := T;
APreset := Presets[T];
//the following lines are an adaptor so that the Active Preset's
//properties are editable directly via T{Cust}Ramugen
AName := APreset.PresetName;
APitch := APreset.Pitch;
ADuration := APreset.Duration;
AAmplitude := APreset.Amplitude;
AArticulation := APreset.Articulation;
AAggregateDelay := APreset.AggregateDelay;
ANumNotes := APreset.NumNotes;
ATransposeFactor := APreset.TransposeFactor;
AMoveInterval := APreset.MoveInterval;
AChordIntervals := APreset.ChordIntervals;
AMoveHand := APreset.MoveHand;
AChangeLandmark := APreset.ChangeLandmark;
AActivateLandmark := APreset.ActivateLandmark;
ABackTrack := APreset.BackTrack;
ARest := APreset.Rest;
AChordLocal := APreset.ChordLocal;
end;
procedure TCustRamugen.SetActiveMood(T : Integer);
begin
if T < 0 then T := 0;
if T > 127 then T := 127;
FActiveMood := T;
AMood := Moods[T];
APresetChange := AMood.PresetChange;
end;
procedure TCustRamugen.SetActiveMindset(T : Integer);
begin
if T < 0 then T := 0;
if T > 127 then T := 127;
FActiveMindset := T;
AMindset := Mindsets[T];
AMoodChange := AMindset.MoodChange;
end;
procedure TCustRamugen.SetPFilled(T : Boolean);
begin
APreset.FFilled := T;
end;
procedure TCustRamugen.SetMFilled(T : Boolean);
begin
AMood.FFilled := T;
end;
procedure TCustRamugen.SetSFilled(T : Boolean);
begin
AMindset.FFilled := T;
end;
procedure TCustRamugen.SetPresetName(T : String);
begin
APreset.FName := T;
end;
procedure TRamugen.SetBrainInterval(T: Integer);
begin
BrainTimer.Interval := T;
end;
function TRamugen.GetBrainInterval : Integer;
begin
Result := BrainTimer.Interval;
end;
//Property Setters
//TCustRamugen direct data access array property setters
procedure TCustRamugen.SetPreset(P : Integer; Value : TRamugenPreset);
begin
Presets[P] := Value;
end;
procedure TRamugen.SetStartPlaying(X : TNotifyEvent);
begin
FOnStart := X;
end;
procedure TRamugen.SetStopPlaying(X : TNotifyEvent);
begin
FOnStop := X;
end;
procedure TRamugenPreset.SetPName(T : String);
begin
FName := T;
end;
function TCustRamugen.SetNoteSub(T : Integer) : Integer;
begin
if T < APreset.Pitch.Min then T := APreset.Pitch.Min;
if T > APreset.Pitch.Max then T := APreset.Pitch.Max;
Result := T;
end;
procedure TCustRamugen.SetNote(T : Integer);
begin
FNote := SetNoteSub(T);
end;
procedure TCustRamugen.SetNote2(T : Integer);
begin
FNote2 := SetNoteSub(T);
end;
procedure TCustRamugen.SetNote3(T : Integer);
begin
FNote3 := SetNoteSub(T);
end;
procedure TCustRamugen.SetNote4(T : Integer);
begin
FNote4 := SetNoteSub(T);
end;
procedure TCustRamugen.SetNote5(T : Integer);
begin
FNote5 := SetNoteSub(T);
end;
procedure TCustRamugen.SetNote6(T : Integer);
begin
FNote6 := SetNoteSub(T);
end;
procedure TCustRamugen.SetAmplitude(T : Integer);
begin
if T < APreset.Amplitude.Min then T := APreset.Amplitude.Min;
if T > APreset.Amplitude.Max then T := APreset.Amplitude.Max;
FAmplitude := T;
end;
procedure TCustRamugen.SetDuration(T : Integer);
begin
if T < APreset.Duration.Min then T := APreset.Duration.Min;
if T > APreset.Duration.Max then T := APreset.Duration.Max;
FDuration := T;
end;
procedure TCustRamugen.SetMIDIDevice(T : Integer);
begin
if T < -1 then T := -1;
if T > 8 then T := -1; //Ideally, this should be calculated; 8 is correct on MY computer
FMIDIDevice := T;
MidiOutClose(midihandle);
MidiOutOpen(addr(MidiHandle), MidiDevice, 0, 0, 0);
FMIDIArray.Handle := MidiHandle;
end;
procedure TCustRamugen.SetMIDIVoice(T : Integer);
begin
if T < 0 then T := 0;
if T > 127 then T := 127;
FMIDIVoice := T;
MidiOutShortMsg(MidiHandle, $C0 + FMIDIChannel + FMIDIVoice shl 8 + 0 shl 16);
end;
procedure TCustRamugen.SetMIDIChannel(T : Integer);
begin
if T < 0 then T := 0;
if T > 127 then T := 127;
FMIDIChannel := T;
FMIDIArray.Channel := FMIDIChannel;
end;
procedure TRamugen.SetPlaying(T : Boolean);
begin
FPlaying := T;
if FPlaying then begin
MIDITimer.Enabled := true;
if devolvees <> [] then BrainTimer.Enabled := true;
end
else begin
MIDITimer.Enabled := true;
BrainTimer.Enabled := false;
Memory.Halt;
end;
end;
procedure TCustRamugen.SetMoodWeightings;
begin
AMood.Title := 'Mood #' + inttostr(ActiveMood);
AMood.Description :=
'Assign a value to the various stored presets so that, when this mood prevails, they determine the likelihood of each preset being used at any given time.';
AMood.InputWeightings(0, PresetCount -1);
end;
procedure TCustRamugen.SetMindsetWeightings;
begin
AMindset.Title := 'Mindset #' + inttostr(ActiveMindset);
AMindset.Description :=
'Assign a value to the various stored presets so that, when this mindset prevails, they determine the likelihood of each mood being used at any given time.';
AMindset.InputWeightings(0, MoodCount -1);
end;
//user interface ease-of-use Setters (methods make more sense here)
procedure TRamugen.Start;
begin
playing := true;
if Assigned(FOnStart) then FOnStart(Self); //optional custom events
end;
procedure TRamugen.Stop;
begin
playing := false;
if Assigned(FOnStop) then FOnStop(Self);
end;
// Getters
function TCustRamugen.GetPreset(P: Integer) : TRamugenPreset;
begin
Result := Presets[P];
end;
function TCustRamugen.GetPresetCount : Integer;
var t: Integer;
begin
Result := 0;
for t := 0 to 127 do begin
if Presets[t].FFilled then inc(Result) else break;
end;
end;
function TCustRamugen.GetMoodCount : Integer;
var t: Integer;
begin
Result := 0;
for t := 0 to 127 do begin
if Moods[t].FFilled then
begin inc(Result);
end
else break;
end;
end;
function TCustRamugen.GetMindsetCount : Integer;
var t: Integer;
begin
Result := 0;
for t := 0 to 127 do begin
if Mindsets[t].FFilled then inc(Result) else break;
end;
end;
function TCustRamugen.GetPFilled : Boolean;
begin
Result := APreset.FFilled;
end;
function TCustRamugen.GetMFilled : Boolean;
begin
Result := AMood.FFilled;
end;
function TCustRamugen.GetSFilled : Boolean;
begin
Result := AMindset.FFilled;
end;
function TRamugenPreset.GetPName : String;
begin
Result := FName;
end;
//Misc. internal
procedure TCustRamugen.SetDefaults;
var t : integer;
begin
for t := 127 downto 0 do
begin
ActivePreset := t;
Duration.SetRange(100,1000);
Duration.UnitSize := 100;
AggregateDelay.Max := 0;
Amplitude.SetRange(80,110);
Pitch.SetRange(40,80);
Pitch.Title := 'Pitch';
Pitch.Change.Probability := 1;
Articulation.HardMax := 30000;
Articulation.SetRange(5000,5000);
NumNotes.HardMax := 6;
NumNotes.HardMin := 1;
NumNotes.SetRange(1,1);
PresetName := 'Untitled';
TransposeFactor.Max := 0;
TransposeFactor.Title := 'Transposition Factor';
TransposeFactor.Description := 'These values are used to simulate "key changes".';
MoveInterval.Title := 'Hand Emulation';
end;
end;
// Low-level MIDI encapsulation for end-users - functionality provided by TMidiArray worker object
procedure TCustRamugen.StartNote(pitch, amplitude : Integer);
begin
FMIDIArray.StartNote(pitch, amplitude);
end;
procedure TCustRamugen.StartNote(NoteName : string; Octave : Integer = 5; dynamicmarking : string = 'mf');
begin
FMIDIArray.StartNote(NoteName, Octave, DynamicMarking);
end;
procedure TCustRamugen.StopNote(pitch : Integer);
begin
FMIDIArray.StopNote(Pitch);
end;
procedure TCustRamugen.StopNote(NoteName : string; Octave : Integer = 5);
begin
FMIDIArray.StopNote(NoteName, Octave);
end;
procedure TCustRamugen.PlayNote(Pitch: Integer; Duration: Integer=700; Amplitude: Integer=100);
begin
FMIDIArray.PlayNote(Pitch, Duration, Amplitude);
if FStoreToArray then FMIDIArray.AddNote(pitch,duration,amplitude);
end;
procedure TCustRamugen.PlayNote(NoteName : string; Octave : Integer = 5; duration : Integer = 700; dynamicmarking : string = 'mf');
var n, v : Integer;
begin
n := NoteNametoNoteValue(NoteName, Octave);
v := 80; //'mf'
if dynamicmarking = 'pppp' then v := 25;
if dynamicmarking = 'ppp' then v := 37;
if dynamicmarking = 'pp' then v := 49;
if dynamicmarking = 'p' then v := 60;
if dynamicmarking = 'mp' then v := 70;
if dynamicmarking = 'f' then v := 90;
if dynamicmarking = 'ff' then v := 103;
if dynamicmarking = 'fff' then v := 115;
if dynamicmarking = 'ffff' then v := 127;
if n = 255 then begin v := 0; n := 1; end;
if FStoreToArray then FMIDIArray.AddNote(n, Duration, v);
FMIDIArray.PlayNote(n, Duration, v);
end;
procedure TCustRamugen.ClearMemory;
begin
FMIDIArray.Clear;
end;
procedure TCustRamugen.AddNote(pitch : integer; duration : integer = 700; amplitude : integer = 100);
begin
FMIDIArray.AddNote(pitch,duration,amplitude);
end;
procedure TCustRamugen.PlayPhrase (TranspositionFactor : Integer = 0; SpeedPercent : Integer = 100);
begin
FMIDIArray.PlayPhrase(TranspositionFactor,SpeedPercent);
end;
procedure TCustRamugen.PlayArray(Pitches : array of Integer; Duration : Integer = 700; Amplitude : Integer = 100; TranspositionFactor : Integer = 0; SpeedPercent : Integer = 100);
begin
FMIDIArray.Assign(Pitches, Duration, Amplitude);
PlayPhrase(TranspositionFactor, SpeedPercent);
end;
procedure TCustRamugen.PlayArray(Pitches : array of Integer; Durations : array of Integer; Amplitude : Integer = 100; TranspositionFactor : Integer = 0; SpeedPercent : Integer = 100);
begin
FMIDIArray.Assign(Pitches,Durations);
PlayPhrase(TranspositionFactor, SpeedPercent);
end;
procedure TCustRamugen.PlayArray(Pitches : array of Integer; Durations : array of Integer; Amplitudes : array of integer; TranspositionFactor : Integer = 0; SpeedPercent : Integer = 100; AmplitudeLowerLimit : Integer = 40; AmplitudeHigherLimit : Integer = 127);
begin
FMIDIArray.Assign(Pitches, Durations, Amplitudes);
PlayPhrase(TranspositionFactor, SpeedPercent);
end;
//Default event-handler for picking presets, etc.
//This can be over-ridden by assigning the TEO_02_Brain event
procedure TRamugen.BrainTimerDefault(Sender : TObject);
begin
BrainTimer.Enabled := false;
if Devolvees = [] then exit;
if dvPresets in Devolvees then begin //pick a preset
if PresetChange.IsRequired then
ActivePreset := AMood.Choose(0,PresetCount - 1);
end;
if dvMoods in Devolvees then begin //pick a mood
if MoodChange.IsRequired then
ActiveMood := AMindset.Choose(0,MoodCount - 1);
end;
{ if dvMindsets in Devolvees then begin //pick a mindset
if MindsetChange.IsRequired then
//need a mechanism for picking mindsets!!! another TWeightingSystem
// ActiveMindset := trunc(random(MindsetCount) - 1);
end;
}
BrainTimer.Interval := 1000 + trunc(random(5000));
BrainTimer.Enabled := true;
end;
{****************************************************************
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
MIDITimer.Enabled := false;
if not playing then exit;
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, t : Integer;
begin
zA := CurrentAmplitude; if Rest.IsRequired then zA := 0;
StartNote(FNote, zA);
t := NumNotes.Choose;
if t > 1 then StartNote(FNote2, zA);
if t > 2 then StartNote(FNote3, zA);
if t > 3 then StartNote(FNote4, zA);
if t > 4 then StartNote(FNote5, zA);
if t > 5 then StartNote(FNote6, zA);
if FStoreToArray then AddNote(Fnote, CurrentDuration,zA);
MIDITimer.Interval := CurrentDuration;
if FSkipEngine then MIDITimer.Interval := 10;
if playing then MIDITimer.Enabled := true else EngineStopNote(nil);
end;
//Register Components for the VCL
procedure Register;
begin
RegisterComponents('Ramugen' , [TRamugen, TRamugenPreset, TMidiArray]);
end;
end.