Search code examples
delphi-7waveout

Cannot hear a beep sound with waveOut API


I just want to produce a beep at 1200hz for 1 second.

This unit loads WaveAPI at start, should play a beep for 1 second, and close WaveAPI at end.

But when running, I can only hear a little noise.

Nothing to say in particular, should be stereo channels, and coded as 2 SmallInt (short in C++) for Left and Right.

The volume is not integrated but is considered as 100% for both channels.

This is my Delphi 6 code:

unit C4Audio;

interface

uses Windows;

type
  TAudioBits  = SHORT;
  TAudioDelay = WORD;
  TAudioHerz  = WORD;

  TAudioByte = record
                     Left, Right : TAudioBits;
               end;

  TAudioStereo = record
                       Left, Right : 0..100;
                 end;
implementation

uses Forms,
     mmsystem;

var
  AudioAPI    : hWaveOut;
  AudioBuffer : array of TAudioByte;
  AudioHeader : TWaveHdr;
  AudioStyle  : TWaveFormatEx;

var _alpha   : Real;
    _cursor  : Integer;
    _high    : Integer;

initialization
               with AudioStyle
                    do begin
                            wFormatTag      := WAVE_FORMAT_PCM;
                            nChannels       := 2;
                            nSamplesPerSec  := 44100;
                            wBitsPerSample  := SizeOf(TAudioBits) * 8;
                            nBlockAlign     := (wBitsPerSample div 8) * nChannels;
                            nAvgBytesPerSec := nBlockAlign * nSamplesPerSec;
                            cbSize          := 0;
                       end;

               if waveOutOpen(@AudioAPI, WAVE_MAPPER, @AudioStyle, 0, 0, CALLBACK_NULL) = MMSYSERR_NOERROR
                  then begin
                            SetLength(AudioBuffer, 1000);

                            with AudioHeader
                                 do begin
                                         dwBufferLength := Length(AudioBuffer) * SizeOf(TAudioByte);
                                         dwFlags        := 0;
                                         dwLoops        := $FFFF;
                                         lpData         := @AudioBuffer;
                                    end;

                            _alpha := 0;
                            _high  := High(TAudioBits);

                            for _cursor := Low(AudioBuffer) to High(AudioBuffer)
                                do begin
                                        AudioBuffer[_cursor].Left  := Round(_high * Sin(_alpha));
                                        AudioBuffer[_cursor].Right := Round(_high * Sin(_alpha));

                                        _alpha := _alpha  + 2 * PI * 1200 / AudioStyle.nSamplesPerSec;
                                   end;

                            if (waveOutPrepareHeader(AudioAPI, @AudioHeader, SizeOf(TWaveHdr)) = MMSYSERR_NOERROR)
                               and
                               (waveOutWrite(AudioAPI, @AudioHeader, sizeof(TWaveHdr)) = MMSYSERR_NOERROR)
                               then Sleep(1000);
                      end
                  else
                    AudioAPI := 0;

finalization
            if AudioAPI <> 0
              then begin
                        while waveOutUnprepareHeader(AudioAPI, @AudioHeader, SizeOf(TWaveHdr)) = WAVERR_STILLPLAYING
                              do Application.ProcessMessages;

                        if waveOutClose(AudioAPI) = MMSYSERR_NOERROR
                           then begin
                                end;
                   end;
end.

Solution

  • You are assigning the wrong pointer value to AudioHeader.lpData.

    AudioBuffer is a dynamic array, so it is just a pointer to data that is held elsewhere in memory.

    When you use @AudioBuffer, that gives you the address of the array's internal pointer that is pointing at the audio data. It does not give you the address of the audio data itself. This is likely the root of your issue.

    You need to instead use either lpData := @AudioBuffer[0] or lpData := Pointer(AudioBuffer) to make lpData point at the actual audio data.