Link to home
Start Free TrialLog in
Avatar of JacekH
JacekHFlag for Poland

asked on

WaveOutStream - playing wave in WinApi

A part of my simple code:

const
  memBlockLength = 512;

type
  Tmemblock = array[0..memBlockLength] of byte;
  PmemBlock = ^TmemBlock;
  TWaveheader = packed record
    RiffID: array [1..4] of char;
    RiffLen: LongWord;
    WaveID: array [1..4] of char;
    FmtID: array [1..4] of char;
    FmtLen: LongWord;
    FormatTag: Word;
    nChannels: Word;
    nSamplesPerSec: LongWord;
    nAvgBytesPerSec: LongWord;
    nBlockAlign: Word;
    wBitsPerSample: Word;
    DataID: array [1..4] of char;
    DataLen: LongWord;
  end;

var
  OutPort:  HWAVEOUT;
  WvOutFmt: ^TWAVEFORMATEX;
  f: File;
  HeaderF: TWaveHeader;
  Header: PWaveHdr;
  OneBlock: PmemBlock;
  MMoRes: MMResult;

----------------------------------
  if OpenDialog1.Execute then
  begin
    AssignFile(F, OpenDialog1.FileName);
    Reset(F,1);
    BlockRead(F, HeaderF, 44);  
   
    New(WvOutFmt);
    with WvOutFmt^ do
    begin
      wFormatTag := WAVE_FORMAT_PCM;
      nChannels := HeaderF.nChannels;
      nSamplesPerSec := HeaderF.nSamplesPerSec;
      nAvgBytesPerSec := HeaderF.nAvgBytesPerSec;
      nBlockAlign := HeaderF.nBlockAlign;
      wBitsPerSample := HeaderF.wBitsPerSample;
      cbSize := 0;
    end;
// lbDevCaps.ItemIndex - my audiocard outs (WaveOutGetDevCaps)
    OutPort := waveOutOpen(Nil, lbDevCaps.ItemIndex, @WvOutFmt, Form1.handle, 0, WAVE_ALLOWSYNC or CALLBACK_WINDOW);
    FreeMem(WvOutFmt);
-----------------------------------------------------
And here is my problem. What should I do next do play that wave file? I tried something stupid ... like this:

  New(OneBlock);
  Header := New(PWaveHdr);
  BlockRead(F, OneBlock, SizeOf(OneBlock));
  with Header^ do
  begin
    lpdata := pointer(OneBlock);
    dwbufferlength := memblocklength;
    dwBytesRecorded := 0;
    dwUser := 0;
    dwFlags := 0;
    dwLoops := 0;
  end;
  MMoRes := waveOutPrepareHeader(OutPort, Header, SizeOf(Header));
  MMoRes := waveOutWrite(OutPort, Header, SizeOf(Header));
 
And of course it doesn't work. Could anybody give me an example of wave streaming API procedures? waveOutOpen - I'm not sure if I'm doing it right (callback??). How should I read and prepare blocks (waveOutPrepareHeader), and then send them (waveOutWrite) to audio device? Also how to use callback to get end of wave file? I need to play two different wave files (the same sample rate/freq. etc.) to different outputs of my audio card with perfect sample accurate. Could you help?

Jacek
Avatar of Lee_Nover
Lee_Nover

what do you mean to different outputs ? front/rear speakers ?
deAudio (commercial) does it nicely .. and much much more :)
Avatar of JacekH

ASKER

My audio card (RME HDSP + Mutliface) has 18 outputs - 9 stereo pairs: 8 x analog outs, 1x ADAT (8 outs) and one SPDIF (stereo). I don't want to use any other components like deAudio. I tried with BASS, FMOD. BASS cannot play waves to different outputs in perfect sync. FMOD cannot play to more one than one stereo output at all, only with multiple channel files prepared with special program. And first of all I want to learn how to do it. Typical multitrack editor plays tracks mixing them to one outputs. More advanced can play each track to individual output - that's what I need. But - I need to know to play one file properly... :-)

Jacek
ASKER CERTIFIED SOLUTION
Avatar of gmayo
gmayo
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
oh yes .. DirectSound :)
I've started something but never finished .. the playing part works fine
you only need to find out how to set on what output to play :)

http://leenover.homeip.net/isapi/pas2html.dll/pas2html?File=/delphi/lnDS
Avatar of JacekH

ASKER

Lee_Nover - I tried your codes but there some errors. And I'd like to learn hot to play it with WinAPI. So - maybe any suggestion to play one file ;-) but not with SoundPlay or MediaPlayer ;-) 'Real' wave streaming.

?

Jacek
there should be no errors .. there just isn't the complete implementation - no sample app
you're obviously missing some units .. my guess is DirectSound from delphi-jedi
I didn't say that it's a complete product :) .. that's the base point to help you start if you go for DirectSound
Avatar of JacekH

ASKER

I have DirectSound (Jedi). What I did: just new project doingo nothing - only uses included,

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,lnDSound, lnDSAudio, lnCapiAudio, lnBuffer;

All found.  But:
unit lnDSAudio;  
*** Undeclared identifier
    FDSIn: TlnDSIn;
    FDSOut: TlnDSOut;
-----------------------------
Is DirectSound the only solution? How can I play using WinAPI? :(

Jacek
Have you tried the Clootie headers (not Jedi)?

Geoff M.
omg ! these jedi headers are totaly ****ed up .. names changed in structures and params in functions .. lovely

you only need TlnDSBuffer and TlnDSOut from unit lnDSAudio
JacekH

Have you tried the PlaySound function in the winmm.dll ??

Do a tdump on the dll, I think the function name is : PlaySoundA

Regards
 Engwi
Avatar of JacekH

ASKER

I do need that code :( I used Turbo Pascal year ago and I'm quite new to Object Pascal. So I need a good example [comments are welcome ;-)]   Well, let's try with simpler question. Please, give me a full example of project to play wave with streaming, not loading the whole file to RAM and using PlaySound or MediaPlayer. It should can play even 1 hour long wave file, started with opening the port, preparing buffers etc. and finally callback a message at the end of playing. I've increased to 400 points.

Jacek
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ooops. Sorry. I've posted to wrong thread. Sorry again.

Nevertheless if you translate my code to pascal it'll be a solution ;-)
Here is the Delphi code:

///////////////////////////////////////
unit th_splayer;

interface

uses
  Classes, mmsystem;

type
  KSPlayer = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation


{ KSPlayer }

procedure KSPlayer.Execute;
begin
  { Place thread code here }
  while not Terminated do begin
    PlaySound('siren.wav', 0, 0);
  end;
end;

end.
////////////////////////////////////////
reread the question guys ... he needs to play the sound at different outputs !
PlaySound and alike use the default output
Avatar of JacekH

ASKER

GloomyFriar:
I wrote about PlaySound. It's not a solution, look above why.

I spent a lot of time and finally have found a code at Borland - the old one recorder/player. It looks that's what I need. Almost. Almost because it plays one file to one output. I'm not sure if I can play two files in perfect sample sync using this code. Maybe threads... I'll try. But question is still valid - if you have a good simple code [with comments ;-) ]  I'll pay all these 400 points.

Jacek
it's an interesting thing and I'd look into it if I had time
>Almost because it plays one file to one output.
To play to different devices, use different device handlers.

>I'm not sure if I can play two files in perfect sample sync using this code.
I think, It's impposible, if you hardware have not some special function for it.
>Almost because it plays one file to one output.
To play to different devices, use different device handlers.

>I'm not sure if I can play two files in perfect sample sync using this code.
I think, It's impposible, if you hardware have not some special function for it.
Avatar of JacekH

ASKER

From MM SDK:
"The sndPlaySound and PlaySound functions load an entire waveform-audio file into memory and, in effect, limit the size of file they can play. Use sndPlaySound and PlaySound to play waveform-audio files that are relatively small ľ up to about 100K. These two functions also require the sound data to be in a format that is playable by one of the installed waveform-audio drivers, including the wave mapper."

So it's not streaming.

How about OpenASIO?

Jacek
I can give you the sample code showing how to play sound with waveOutOpen/waveOutPrepareHeader/waveOutWrite.
But the sample in C not Delphi.