JacekH
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(OutPo rt, 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
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(OutPo
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
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
Jacek
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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
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
?
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
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
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
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.
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
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
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
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
Jacek
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Ooops. Sorry. I've posted to wrong thread. Sorry again.
Nevertheless if you translate my code to pascal it'll be a solution ;-)
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.
////////////////////////// ////////// ////
//////////////////////////
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
PlaySound and alike use the default output
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
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.
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.
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.
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
"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/waveOutPrepare Header/wav eOutWrite.
But the sample in C not Delphi.
But the sample in C not Delphi.
deAudio (commercial) does it nicely .. and much much more :)