这是我在此处How can I play a single tone or custom wave with Delphi?
提出的另一个问题的跟进总而言之,我使用MMSystem的waveOutWrite()创建了一个离散信号,但它似乎没有像我预期的那样工作,或者我没有得到它。
我使用固定空格向缓冲区写了两个离散信号,如Samples[i] := round(vol*sin(2*Pi*AFreq*t));
对于信号,音量为1000,而“空格”为0伏特信号。
这就是我想要的东西,就像| ... |
我收到Signal的所有错误还是我没有正确使用WinAPI?我希望每个固定信号在图上看起来都一样
P.S:我正在使用Windows的立体声混音,所以没有干扰 P.P.S:这是将Binary转换为Signal
的代码段function CreateBinaryTone(BinaryString: String): TWaveformSamples;
var
I: Integer;
omega,
dt: double;
vol: double;
begin
omega := 2*Pi*AFreq;
dt := 1/Format.nSamplesPerSec;
SetLength(Samples, Length(BinaryString));
for I := 1 to Length(BinaryString) do
begin
{ Discrete Time }
Vol := StrToInt(BinaryString[I]) * 1000;
Samples[I] := vol * sin(omega * dt * I);
end;
Result := Samples;
end;
答案 0 :(得分:2)
您的位时间需要比载波(正弦)频率的周期长得多,并且采样率也需要超过载波频率的2倍。因此,您的样本生成循环可能需要更长的时间。
答案 1 :(得分:1)
我可能在这个线程上发布得很晚,但是,如果要点是创建一个可以产生离散而又连续的正弦/余弦信号而又不考虑时间的函数(例如没有可预测时间限制的实时操作),那很容易,但有效的方法!
首先,数学:
我们的朋友欧拉(Euler)为我们提供了一种使用复数描述正弦和余弦的方法。
通过在该方程式中添加时间变量,我们可以使其描述正弦波和余弦波
在这个算术中,余弦波由该复数的实数部分表示 和我们的余弦波的虚部:
Euler - Actual Sin/Cos Presentation
现在,每次我们增加此时间变量时,就像我们将旋转量增加了一个小角度(我们称其为theta或θ)。这意味着我们下一步,与上一步具有一个角度加上这个小θ角
请记住,我们将ωt视为最后一步 和θ的角度,作为需要添加的角度到最后一步的角度,以便生成新步骤。
如果我们开发此等式的左侧,将会看到有趣的事情发生
我们知道,如果一个复数 z 与另一个复数 w 相等,则意味着它们的实部和虚部也相等。
记住这一点,我们看到一个非常有趣的结论: 如果我们已经计算出了最后一步的正弦和余弦值,则可以通过添加此θ角来轻松地计算下一步,相应地使用以下方程式计算余弦和正弦值:
Euler - Next Step Calculation Equations
最后, 编码部分
现在,要创建这样的功能,您将需要一些东西:
首先,声明:
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;
下一步是实现:
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;
在此示例中,应在每次程序启动时(也就是在第一次SineGen / CosineGen调用之前)以及每次您要重置wave时调用Init过程。
编辑:更正的图像+添加了被遗忘的初始化过程