2007. május 17., csütörtök
How to create stereo wave files with accurate frequencies
Problem/Question/Abstract:
How do I generate low frequency audio < 1000 Hz with one frequency to the left channel and a slightly different frequency to the right? For example , a tone of 400 Hz is presented to the right ear and a tone of 410 Hz is presented simultaneously to the left ear ? I'm trying to write a small binaural beat test program. I understand the science but not how to generate the two tones in Windows.
Answer:
Assuming you want precise control over the waveforms, the best thing to do is to create a stereo .WAV file containing the desired data. Here's a function that will do that; you can adapt it to your needs (add MMSystem to your USES list):
procedure CreateSineWave(LeftFreq, RightFreq: Single; Duration: Cardinal; const FileName: string);
const
BitsPerSample = 16;
NumChannels = 2;
SampleRate = 44100;
var
ChunkSize: Integer;
DataSize: Integer;
Factor: Single;
Format: TWaveFormatEx;
FourCC: array[0..3] of Char;
I: Integer;
NumSamples: Integer;
L: SmallInt;
R: SmallInt;
WaveStream: TFileStream;
begin
WaveStream := TFileStream.Create(FileName, fmCreate);
try
FourCC := 'RIFF';
WaveStream.Write(FourCC, SizeOf(FourCC));
NumSamples := (SampleRate * Duration) div 1000;
DataSize := (BitsPerSample shr 3) * NumChannels * NumSamples;
ChunkSize := DataSize + SizeOf(TWaveFormatEx) + 20;
WaveStream.Write(ChunkSize, SizeOf(ChunkSize));
FourCC := 'WAVE';
WaveStream.Write(FourCC, SizeOf(FourCC));
FourCC := 'fmt ';
WaveStream.Write(FourCC, SizeOf(FourCC));
ChunkSize := SizeOf(TWaveFormatEx);
WaveStream.Write(ChunkSize, SizeOf(ChunkSize));
with Format do
begin
wFormatTag := WAVE_FORMAT_PCM;
nChannels := NumChannels;
nSamplesPerSec := SampleRate;
wBitsPerSample := BitsPerSample;
nBlockAlign := nChannels * wBitsPerSample shr 3;
nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
cbSize := 0
end;
WaveStream.Write(Format, SizeOf(Format));
FourCC := 'data';
WaveStream.Write(FourCC, SizeOf(FourCC));
ChunkSize := DataSize;
WaveStream.Write(ChunkSize, SizeOf(ChunkSize));
for I := 0 to 999 do
begin
Factor := Exp(-0.005 * (1000 - I));
L := Round(Factor * 32767 * Sin(2 * Pi * LeftFreq * I / SampleRate));
R := Round(Factor * 32767 * Sin(2 * Pi * RightFreq * I / SampleRate));
WaveStream.Write(L, SizeOf(L));
WaveStream.Write(R, SizeOf(R))
end;
for I := 1000 to NumSamples - 1001 do
begin
L := Round(32767 * Sin(2 * Pi * LeftFreq * I / SampleRate));
R := Round(32767 * Sin(2 * Pi * RightFreq * I / SampleRate));
WaveStream.Write(L, SizeOf(L));
WaveStream.Write(R, SizeOf(R))
end;
for I := NumSamples - 1000 to NumSamples - 1 do
begin
Factor := Exp(0.005 * (NumSamples - 1001 - I));
L := Round(Factor * 32767 * Sin(2 * Pi * LeftFreq * I / SampleRate));
R := Round(Factor * 32767 * Sin(2 * Pi * RightFreq * I / SampleRate));
WaveStream.Write(L, SizeOf(L));
WaveStream.Write(R, SizeOf(R))
end;
WaveStream.Position := 0;
finally
WaveStream.Free
end
end;
So, for example, to create a two-second sample having a 400 Hz left channel and a 410 Hz right channel:
CreateSineWave(400.0, 410.0, 2000, 'foo.wav');
You can play the sound like this:
sndPlaySound('foo.wav', SND_SYNC);
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése