Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Retrieving samples with DirectX/DirectSound (Read 8644 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Retrieving samples with DirectX/DirectSound

Hi All,

I am trying to retrieve audio data in 24bit (32bit) Float format using DirectSound,
or similar interface, the ISyncReader? Or is there more that I have missed in the
last couple of days of reading?

So I simply just want to read a sound file, get the buffers, do some calculation
and throw the buffer away. Please note, I do not need to play the buffer,
just need the 32-bit floats.

Anybody have any suggestions on how I need to get these?
Can anyone give me some directions?

Thanks for helping!
Eric

Retrieving samples with DirectX/DirectSound

Reply #1
Hi All,

I am trying to retrieve audio data in 24bit (32bit) Float format using DirectSound,
or similar interface, the ISyncReader? Or is there more that I have missed in the
last couple of days of reading?

So I simply just want to read a sound file, get the buffers, do some calculation
and throw the buffer away. Please note, I do not need to play the buffer,
just need the 32-bit floats.

Anybody have any suggestions on how I need to get these?
Can anyone give me some directions?

Thanks for helping!
Eric

Why are you talking about DirectSound when you don't need to play the file?
I think you mistook DirectSound for DirectShow, which is now a part of Windows SDK/API rather than DirectX. DirectShow is an universal API for multimedia applications (multimedia coding/decoding/playback/recording/capture etc.).

If your input file is a WAV file, you don't even need DirectShow, just read the WAV header and the raw PCM data. If you need 32-bit float format, just convert the integer samples to floats in your program (and divide them by the maximum value the integral sample can hold so you get them to <-1.0;1.0) range). This is trivial for 16-bit depth and a little bit harder for 24-bit one (samples are not aligned as you would need).

If your input file is a compressed one, you will probably need to use DirectShow or a specific decoder.

What programming language/development environment do you use?

Retrieving samples with DirectX/DirectSound

Reply #2
Hi

I actually use delphi.

I currently read files for playing by setting up a primary and secundary buffer,
(using IDIrectSound.CreateBuffer) and reading sample data with the ISampledata
interface. But this is all done in 16bit.

This works all very well for playing a file, but I dont want to play the file in this
instance, I want to read the 24 or 32bit floating points to do a calculation of the
peak RG value. For any given file that has a corresponding directshow filter,
i.e. could be an mp3, flac, etc..

The problem is that I can't seem to set the waveextensible format to the sample,
only to the Directsound buffer. So I don't understand how to just retrieve samples
in 24bit/32bit float.

And all the examples I have read sofar talk about playing streams and getting the
data, but I dont want to play the file, I just want to quickly get data, calc the peak,
get the next data, etc. till I processed all the data in the file, get next file.

Regards,
Eric

p.s.
I do need 24bit resolution, to calcualte any values above 1.0, as Foobar does.
Peak values can actually be over 1.0 as I learned in this forum, and as such I
would need the 24bit for the calcualtion. I can retrieve 24bit data with BASS
and can calculate the peaks identical to foobar with bass, but I want to support
both BASS and DirectShow filters, and maybe later even other plugins.

FYI, it is for a freeware product, www.dajukebox.com/soundbase
So it is for a good cause :-)

Retrieving samples with DirectX/DirectSound

Reply #3
The problem is that no ordinary directshow filter will ever give you float values out of the <-1;1> range - simply because it would violate the specs for the float PCM standard itself and it could cause problems further in DirectShow filter graphs (e.g. for an audio renderer).
You need either a special DirectShow filter for this or use a specific decoder which can output float data without normalization.

If you knew C++, I could give you my DirectShow multimedia grabber library to play around with.

Retrieving samples with DirectX/DirectSound

Reply #4
Hi Martel,

Didnt say I didnt knew C++, just build this part of my app in delphi...
So if you have a lib that I can look into that would be a great help.
Well, you are a great help already!

Thanks,
Eric

Retrieving samples with DirectX/DirectSound

Reply #5
http://martel.ic.cz/filegrabber-04-24-08.zip
It's intended for MS VC++ 2008 Express (free for download on Microsoft website). In the Release directory, there is a compiled demo console application.

But in order to obtain audio as float, you will have to persuade DirectShow to use a specific decoder for the file and moreover that such decoder should decode to 32 bit float.
Normally, decoders output 44/48kHz, 16-bit, mono/stereo regardless of input audio type (multichannel/24-bit/whatever). The trick is to use a configurable decoder filter such as ffdshow audio decoder. It has a GUI configuration utility where you can force it to decode into float/multichannel format. You must also override the default decoder for a specific format so DirectShow will use ffdshow instead of a standard decoder (like built-in WMA decoder). This might, however, need some serious tweaking of codec setup, perhaps manual removal of unwanted decoders (using regsrv32.exe) or boosting ffdshow priority (a.k.a. merit).

You can see what decoder is being used for the file if you save the output of the demo application into file and look at the beginning of it. There is a textual description of the DirectShow filter graph (with filter names, data types etc.).
launch: filegrabberdemo.exe myfile.xyz >log.txt
Then the console (stdout) output will be redirected to log.txt file where you can read it.

The whole project is primarily intended for offline processing of video files, it may be, however, used even for pure audio files as well.

Retrieving samples with DirectX/DirectSound

Reply #6
Hi Martel,

I have a go at it, sounds logical that the default is 16bit, otherwise all those directshow players would be internally in 24bit I guess. Anyway, I'll share my experience on the code back, lets hope I can get it working and make my app work in 24bit (well it already does with bass, but I want to be able to live without bass).

Thanks so much, cheerz,
Eric

Retrieving samples with DirectX/DirectSound

Reply #7
Hi Martel, All,

Sorry, but the more I read, the more I get confused, and more questions come up.

I did install the FFDShow filter and it works with WMP, and when in_directshow is set in winamp, also winamp takes it as the default filter.

Now if I use it in my application, it defaults always to the fraunhofer mp3 filter, and if I disable the fraunhofer (with DSFMgr.exe) then my app just can't play mp3 files at all, in code it gives an error when trying to open the file. It goes wrong already at the openfile call, again only if the fraunhofer is not installed (see attached code). Else everything works fine.

I assume that somewhere I have to set the format tag? To something comparable to the WAVE_FORMAT_MPEGLAYER3? Or am I missing the point, if not, any ideas what value this would need to be? Can't find any ref to it on the internet. If I am missing the point, any suggestions to force a filter or something?

Regards,
Eric

Code: [Select]
      // creates IAMMultiMediaStream instance/directx
      SCheck( CoCreateInstance( CLSID_AMMultiMediaStream, nil, CLSCTX_INPROC_SERVER,
                                IID_IAMMultiMediaStream, FAMMultiMediaStream ) );

      SCheck( FAMMultiMediaStream.Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, nil) );

      // creates IMediaStream instance
      SCheck( FAMMultiMediaStream.AddMediaStream(nil, @MSPID_PrimaryAudio, 0, FMediaStream) );

      SCheck( FAMMultiMediaStream.GetMediaStream(MSPID_PrimaryAudio, FMediaStream) );

      // opens the file
      v := Trim(FileName);

===========================HERE IT GOES WRONG=================
      SCheck( FAMMultiMediaStream.OpenFile(PWideChar(v), AMMSF_NOCLOCK));//EDH0) );

      // Get IMediaControl instance
      SCheck( FAMMultiMediaStream.GetFilterGraph(FGraphBuilder) );
      
      SCheck( FGraphBuilder.QueryInterface(IID_IMediaControl, FMediaControl) );
      SCheck( FGraphBuilder.QueryInterface(IID_IMediaSeeking, FMediaSeeking) );

      // creates IAudioMediaStream instance
      SCheck( FMediaStream.QueryInterface(IID_IAudioMediaStream, FAudioMediaStream) );

      SCheck( FAudioMediaStream.GetFormat(Format) );
      // creates IAudioData instance and set format to audiodata!!
      SCheck( CoCreateInstance(CLSID_AMAudioData, nil, CLSCTX_INPROC_SERVER,
                               IID_IAudioData, FAudioData) );
      SCheck( FAudioData.SetFormat(Format) );

      // creates IAudioStreamSample instance
      SCheck( FAudioMediaStream.CreateSample(FAudioData, 0, FAudioStreamSample) );

      //SCheck( FAMMultiMediaStream.GetInformation(FInformation) );
      SCheck( FAMMultiMediaStream.GetDuration(FLenght) );

      SCheck( FAMMultiMediaStream.SetState( STREAMSTATE_RUN ) );

      FLenght := FLenght div MUNITS_PER_MSEC; //Must be before
      FDuration := (FLenght * Format.Format.nAvgBytesPerSec) div 1000;

      FFileName := FileName;
      FSelLength := 0;
      FPosition := 0;

Retrieving samples with DirectX/DirectSound

Reply #8
I'm still confused about what API you actually use to process the audio file. You use some interface (IAMMultiMediaStream) that I'm not familiar with.

http://msdn2.microsoft.com/en-us/library/ms784028.aspx
Quote
Note - This interface is deprecated. New applications should not use it.


This interface seem much too high-level to me. You probably won't be able to do much with it except play back a file (I think it was designed to automatically build multimedia playback graphs, which is not the graph you need)...

If you need to grab multimedia content into a memory buffer, you will need to manually setup and insert a component named SampleGrabber into the filter graph. My library does something similar but it directly replaces the default renderers (video overlay/soundcard) with my own renderers which just grab the data into a buffer. I also override the default graph clock to run at maximum speed (no realtime playback).

One last note - you usually cannot choose the exact processing format directly in the filter graph as DirectShow uses "Intelligent connect" which means that Windows will decide for you which filters to use in the graph and such filters then offer their prefered multimedia formats to other filters in the graph - there is a negotiation you cannot directly influence. What you can is to use configurable directshow decoder filters with high priority so you can choose their output format in some GUI interface (like the ffdshow one). Some other filters (like WMA audio decoder) expose their configuration directly through their filter interface which is very inconvenient (you have to read and work with some property bags and it all gets messy).

Still, you will not get a float outside the -1;1 range from standard codecs, if this is your intent. You need to use specific decoders for this and set them up somehow so they do not saturate float output at -1.0 and 1.0. I think this is what Foobar2k does, it doesn't rely on any external codecs since they are useless for replaygain purposes.

Retrieving samples with DirectX/DirectSound

Reply #9
Hi Martel,

The interface is indeed depreciated, it should be replaced by an applications own filter.
But my application is running without any drivers or registry access, hence my drive to get access to floats this way, just one executable, nothing else required.

The code I am using merely opens a file, and creates samplebuffers that I read. I copy these raw buffers to a 32bit internal soundbuffer for processing.

The default interface I use is directshow, but I do this also with many other drivers, working on the lib*.dlls now, but also support the winamp and bass dlls, well in alpha only at the moment.

Currently these provide me all with 32 float data and I can calulate the same values as foobar with these drivers (thanks to some help I also received from this forum).

I am just a bit anal about getting directshow also to work in 32bit I guess, I might just need to leave it for the moment, anyone wants 32bit support should then just install the plugins.

Thanks for your time sofar!
Regards,
Eric