I've found the problem.
The sound driver was buggy. My code is OK.
--
francois.pie...@overbyte.be
The author of the freeware multi-tier middleware MidWare
The author of the freeware Internet Component Suite (ICS)
http://www.overbyte.be
----- Original Message -----
From: "Francois PIETTE" <francois.pie...@skynet.be>
To: <delphi@elists.org>
Sent: Saturday, June 13, 2009 11:53 AM
Subject: Generating audio waveforms
Hi !
I'm writing a small application which has to generate audio waveform using
the sound card (PCM, 11025KHz, stereo, 8 bits). I'm using waveOutWrite and
related API function.
For now, I have a single buffer. As I understand, audio samples are one
byte
for left, one byte for right up to the end of buffer.
I compute the waveform (a simple sinusoide for my test, different
frequency
on each channel), store the bytes in the buffer and play the sound. I use
an
oscilloscope to see the generated waveform.
When I set a single channel, that is having one byte with the computed
value
and one byte with value 128, I get the correct waveform shown on the
oscilloscope whatever channel I compute. But when I compute both channels,
I
get strange results: left channel is the
some of computed left channel and a fraction of right channel; right
channel
is the sum of right channel and a fraction of left channel. See attached
screen dump.
I don't understand why this happend !
Any help appreciated.
Actual source code:
const
BUFFERSIZE = 65536; //4860;
PI = 3.14159265358979;
FREQUENCY = 440;
procedure TForm1.Button1Click(Sender: TObject);
var
WFormat : TWaveFormatEx;
WaveHeader : TWaveHdr;
Done : THandle;
HWOut : HWAVEOUT;
I : Integer;
Data : array [0..BUFFERSIZE - 1] of Byte;
X : Extended;
L, R : Extended;
Offset1 : Integer;
Offset2 : Integer;
Caps : TWaveOutCaps;
begin
ZeroMemory(@WFormat, SizeOf(WFormat));
WFormat.wFormatTag := WAVE_FORMAT_PCM;
WFormat.nChannels := 2;
WFormat.wBitsPerSample := 8;
WFormat.nSamplesPerSec := 11025;
WFormat.nBlockAlign := WFormat.nChannels * WFormat.wBitsPerSample
div 8;
WFormat.nAvgBytesPerSec := WFormat.nSamplesPerSec *
WFormat.nBlockAlign;
WFormat.cbSize := 0;
Done := CreateEvent(nil, FALSE, FALSE, nil);
if WaveOutOpen(@hWOut, WAVE_MAPPER, @WFormat, Done, 0, CALLBACK_EVENT)
<> MMSYSERR_NOERROR then begin
ShowMessage('Sound card cannot be opened.');
Exit;
end;
if waveOutGetDevCaps(hWOut, @Caps, SizeOf(Caps)) <> MMSYSERR_NOERROR
then begin
WaveOutClose(hWOut);
ShowMessage('WaveOutGetDevCaps failed.');
Exit;
end;
if (Caps.dwFormats and WAVE_FORMAT_1S08) = 0 then begin
WaveOutClose(hWOut);
ShowMessage('11025KHz 8 bits Mono is not supported');
Exit;
end;
FillChar(Data, BUFFERSIZE, 128);
if ReverseCheckBox.Checked then begin
Offset1 := 1;
Offset2 := 0;
end
else begin
Offset1 := 0;
Offset2 := 1;
end;
// ReverseCheckBox.Checked := not ReverseCheckBox.Checked;
for I := 0 to (BUFFERSIZE div 2) - 1 do begin
if LeftCheckBox.Checked then
L := sin(I * 2.0 * PI * FREQUENCY / WFormat.nSamplesPerSec)
else
L := 0;
if RightCheckBox.Checked then
R := sin(I * 2.0 * PI * 8.0 * FREQUENCY /
WFormat.nSamplesPerSec)
else
R := 0;
// ** scale x to a range of 0-255 (signed char) for 8 bit sound
reproduction **
Data[I + I + Offset1] := Byte(Trunc(127 * L + 128));
Data[I + I + Offset2] := Byte(Trunc(127 * R + 128));
end;
WaveHeader.lpData := PAnsiChar(@Data);
WaveHeader.dwBufferLength := BUFFERSIZE;
WaveHeader.dwFlags := 0;
WaveHeader.dwLoops := 0;
// ** Prepare the header for playback on sound card **
if waveOutPrepareHeader(hWOut, @WaveHeader, SizeOf(WaveHeader)) <>
MMSYSERR_NOERROR then begin
WaveOutClose(hWOut);
ShowMessage('Error preparing Header !');
Exit;
end;
// ** Play the sound! **
ResetEvent(Done); // Reset our Event so it is non-signaled, it will be
signaled again with buffer finished
if waveOutWrite(hWOut, @WaveHeader, SizeOf(WaveHeader)) <>
MMSYSERR_NOERROR then begin
WaveOutClose(hWOut);
ShowMessage('Error writing to sound card !');
Exit;
end;
// ** Wait until sound finishes playing
if WaitForSingleObject(Done,INFINITE) <> WAIT_OBJECT_0 then begin
WaveOutClose(hWOut);
ShowMessage('Error waiting for sound to finish');
Exit;
end;
// ** Unprepare our wav header **
if (waveOutUnprepareHeader(hWOut, @WaveHeader, SizeOf(WaveHeader)) <>
MMSYSERR_NOERROR) then begin
WaveOutClose(hWOut);
ShowMessage('Error unpreparing header !');
Exit;
end;
if WaveOutClose(hWOut) <> MMSYSERR_NOERROR then begin
CloseHandle(Done);
ShowMessage('Sound card cannot be closed.');
Exit;
end;
CloseHandle(Done);
end;
--
francois.pie...@overbyte.be
The author of the freeware multi-tier middleware MidWare
The author of the freeware Internet Component Suite (ICS)
http://www.overbyte.be
--------------------------------------------------------------------------------
_______________________________________________
Delphi mailing list -> Delphi@elists.org
http://lists.elists.org/cgi-bin/mailman/listinfo/delphi
_______________________________________________
Delphi mailing list -> Delphi@elists.org
http://lists.elists.org/cgi-bin/mailman/listinfo/delphi