I may be late posting on this thread, but, if the point is creating a function that generates discrete, yet continuous sine/cosine signal WITHOUT taking time into consideration (ex. RealTime opperations without predictable time limits) there is an easy, yet effective way to do this!
First of all, maths:
Our friend, Euler has provide us a way to describe a Sine and a Cosine, using complex numbers.

By adding a time variable in this equation, we can make it so it describes a sine and a cosine wave

In this ecuatoin, our cosine wave is represented by the Real part of this complex number
and our Cosine wave by its Imaginary part:

Now, every time we increase this time variable, it's just like we are increasing the rotation by a small angle (let's call it theta or θ). That means our next step, sould have an angle of our previous step PLUS this small θ angle
Keep in mind that we will account ωt as the angle of our last step and θ, as the angle that needs to be added to our last step's angle, in order to generate the new step.

If we develop our left side of this equation, we will see something intresting going on there:

As we know, if a complex number z is equal with another complex number w, that means that their real and imaginary parts are also equal.

Having that in mind, we see a very interesting conclusion:
If we have already calculated our last step's Sine and Cosine, we can easily calculate the next step by adding this θ angle, using the equations below for cosine and sine accordingly:

Finaly,
Coding Section
Now, in order to create such function you will need some things:
- 2 global, Double variables, presenting last step's sin and cos
- An init function that sets the initial "step zero" and its initial phase
- A function that calculates and results the next step, when it's being called.
so 1st of all, declarations:
private
[...]
sine_last_cos: double;
sine_last_sin: double;
cosine_last_cos: double;
cosine_last_sin: double;
procedure SineInit(starting_phase: double);
procedure CosineInit(starting_phase: double);
function SineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
function CosineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
Next goes implementations:
procedure Tmain.SineInit(starting_phase: double);
begin
sine_last_sin := sin(starting_phase*pi/180); //given phase is in deg, not rad
sine_last_cos := cos(starting_phase*pi/180);
end;
procedure Tmain.CosineInit(starting_phase: double);
begin
cosine_last_sin := sin(starting_phase*pi/180);
cosine_last_cos := cos(starting_phase*pi/180);
end;
function Tmain.SineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
var sin_theta: double;
cos_theta: double;
new_sin_step, new_cos_step: double;
begin
sin_theta := sin(2*pi*Freq/sampling_rate); //theta depend on sampling freq
cos_theta := cos(2*pi*Freq/sampling_rate); //as well as desirable freq
new_cos_step:= sine_last_cos*cos_theta - sine_last_sin*sin_theta;
new_sin_step:= sine_last_cos*sin_theta + sine_last_sin*cos_theta;
sine_last_sin:= new_cos_step;
sine_last_cos:= new_sin_step;
result := amplitutde *new_sin_step;
end;
function Tmain.CosineGen(amplitutde: double; sampling_rate: Integer; Freq: Double): double;
var sin_theta: double;
cos_theta: double;
new_sin_step, new_cos_step: double;
begin
sin_theta := sin(2*pi*Freq/sampling_rate); //theta depend on sampling freq
cos_theta := cos(2*pi*Freq/sampling_rate); //as well as desirable freq
new_cos_step:= cosine_last_cos*cos_theta - cosine_last_sin*sin_theta;
new_sin_step:= cosine_last_cos*sin_theta + cosine_last_sin*cos_theta;
cosine_last_sin:= new_cos_step;
cosine_last_cos:= new_sin_step;
result := amplitutde *new_sin_step;
end;
In this example, Init procedures should be called every time the program launches (aka before the first SineGen/CosineGen call) and EVERY time you want to reset your wave.
EDIT: Corrected images + added the forgotten Init Procedures