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

Reply via email to