Francois,

 

I don't think the problem is in your code. Is there a balance control
somewhere downstream from your code?  Its behaving as a balance control
would.  Windows?  

 

Best wishes 

Angus

 

Date: Sat, 13 Jun 2009 11:53:31 +0200

From: "Francois PIETTE" <francois.pie...@skynet.be>

Subject: Generating audio waveforms

To: <delphi@elists.org>

Message-ID: <965968643f57493391fb095a439da...@ovb.local>

Content-Type: text/plain; charset="iso-8859-1"; Format="flowed"

 

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

Reply via email to