Author Topic: subclassing the default playback device  (Read 445 times)

gum

  • Posts: 22
subclassing the default playback device
« on: 23 Mar '17 - 17:23 »
I would like to intercept the data being passed to my default audioplayback device to make some modifications. For example, I'd like to apply an audio effect. Also, I'd like to be able to record the data. If I'm getting my point across awsome. I'd also like the feature to be able to just set the data being sent to the playback device to null so I can use it for later while silencing my audio.  Any information on the subject in C# is appreciated.

Ian @ un4seen

  • Administrator
  • Posts: 20272
Re: subclassing the default playback device
« Reply #1 on: 24 Mar '17 - 14:54 »
Do you only want to capture the output from your app, not other apps? If so, it isn't currently possible to capture/modify the BASS output, but it sounds like it would possible to achieve what you want with the BASSmix add-on. You would create a mixer with BASS_Mixer_StreamCreate, and do all playback through that. That would mean using the BASS_STREAM_DECODE flag when creating the streams, and using BASS_Mixer_StreamAddChannel instead of BASS_ChannelPlay to play them. You can then use the mixer handle in BASS_ChannelSetDSP/FX calls to modify the output. If you want to record the output to file, you can use the BASSenc add-on for that; call BASS_Encode_Start with the mixer handle. To minimize latency, you can enable the BASS_ATTRIB_NOBUFFER option on the mixer. The mixer setup could look something like this (on Android/Java):

Code: [Select]
BASS.BASS_INFO info = new BASS.BASS_INFO();
BASS.BASS_GetInfo(info); // get output info
mixer = BASSmix.BASS_Mixer_StreamCreate(info.freq, info.speakers, BASS.BASS_STREAM_DECODE|BASSmix.BASS_MIXER_NONSTOP); // create mixer with same format
BASS.BASS_ChannelSetAttribute(mixer, BASS.BASS_ATTRIB_NOBUFFER, 1); // enable NOBUFFER on mixer

Please see the documentation for details on the aforementioned functions.

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #2 on: 24 Mar '17 - 16:24 »
can you show me a C# example of how to add an effect? or atleast.. how to set the stream to 0 for starters so no sound comes out. but... even though its set to 0 id like to record what WOULD be outputted if i did not set it to zero. kool?

Ian @ un4seen

  • Administrator
  • Posts: 20272
Re: subclassing the default playback device
« Reply #3 on: 24 Mar '17 - 16:41 »
I'm not a C#/.Net user myself, so I'm afraid I can't help much with that, but to mute the output you can simply set the mixer's volume to 0 via its BASS_ATTRIB_VOL setting:

Code: [Select]
BASS.BASS_ChannelSetAttribute(mixer, BASS.BASS_ATTRIB_VOL, 0); // mute the mixer

That won't affect the BASSenc output file or what you receive in your own DSP function.

By the way, will you be playing a single file at a time? If so, you won't actually need a mixer to achieve what you want: you can set the DSP/FX/encoder directly on the file's stream instead then.

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #4 on: 24 Mar '17 - 19:37 »
Hi. Im trying to get this working...

Here's my original code:

Code: [Select]
               
                wi = BassWasapi.BASS_WASAPI_GetInfo(); // get the device's sample format

             
                Bass.BASS_Init(e.Index, 44100, 0, IntPtr.Zero); // initialize the 1st output device
                outputs[e.Index] = Bass.BASS_StreamCreate(wi.freq, wi.chans, BASSFlag.BASS_SAMPLE_FLOAT, BASSStreamProc.STREAMPROC_PUSH); // create a push stream on it with same format as loopback
                Bass.BASS_ChannelPlay(outputs[e.Index], false); // start the 2nd output






It allows me to output to more than one speaker...

I'm trying to get this working with Mixer...
Here's what I Have so far.

Code: [Select]


                Bass.BASS_Init(e.Index, 44100, 0, IntPtr.Zero); // initialize the 1st output device
                                                                // outputs[e.Index] = Bass.BASS_StreamCreate(wi.freq, wi.chans, BASSFlag.BASS_SAMPLE_FLOAT, BASSStreamProc.STREAMPROC_PUSH); // create a push stream on it with same format as loopback

                BASS_INFO info = new BASS_INFO();
                Bass.BASS_GetInfo(info); // get output info

                outputs[e.Index] = BassMix.BASS_Mixer_StreamCreate(info.freq, info.speakers, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_NONSTOP);


                Bass.BASS_ChannelSetAttribute(outputs[e.Index], BASSAttribute.BASS_ATTRIB_NOBUFFER, 1);




                BassMix.BASS_Mixer_StreamAddChannel(outputs[e.Index], info.speakers, BASSFlag. );


i get the error

System.BadImageFormatException: 'An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)'


On line

outputs[e.Index] = BassMix.BASS_Mixer_StreamCreate(info.freq, info.speakers, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_NONSTOP);

can you help? maybe show me the psuedo code cause u dont know much C# and i code it into c# :)

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #5 on: 24 Mar '17 - 20:34 »
I get the following error now.

System.DllNotFoundException: 'Unable to load DLL 'bassmix': This operation is only valid in the context of an app container. (Exception from HRESULT: 0x8007109A)'

radio42

  • Posts: 4559
Re: subclassing the default playback device
« Reply #6 on: 25 Mar '17 - 06:46 »
You typically get a System.BadImageFormatException when you are mixing 32 and 64-bit applications and dlls.
A System.DllNotFoundException indicates, that the bassmixx.dll cannot be found. By default it must be in the same folder as your executable.

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #7 on: 25 Mar '17 - 15:13 »
I've gotten past the crash now here's my situation:

Code: [Select]
                Bass.BASS_Init(e.Index, 44100, 0, IntPtr.Zero); // initialize the 1st output device                                             
                BASS_INFO info = new BASS_INFO();
                Bass.BASS_GetInfo(info); // get output info
                outputs[e.Index] = BassMix.BASS_Mixer_StreamCreate(info.freq, info.speakers, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_NONSTOP);
                Bass.BASS_ChannelSetAttribute(outputs[e.Index], BASSAttribute.BASS_ATTRIB_NOBUFFER, 1);
                BassMix.BASS_Mixer_StreamAddChannel(outputs[e.Index], info.speakers, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_NONSTOP);

No sound comes from my speakers even though I StreamAddChannel them.
« Last Edit: 25 Mar '17 - 15:27 by gum »

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #8 on: 26 Mar '17 - 21:25 »
So, I got the DSP working but it's not quite what I need now that I look at it. It seems I just want to create a "dummy" playback advice, it doesn't need to do *anything* other then be there. Help?

Ian @ un4seen

  • Administrator
  • Posts: 20272
Re: subclassing the default playback device
« Reply #9 on: 27 Mar '17 - 16:14 »
Do you mean you want to capture the output but not hear it? If so, you could mute the mixer via its BASS_ATTRIB_VOL setting (see reply #3 above).

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #10 on: 31 Mar '17 - 21:49 »
Is there a way I can "delay" my default playback using a DSP? maybe putting a 0x00 on the first part of the buffer?

Ian @ un4seen

  • Administrator
  • Posts: 20272
Re: subclassing the default playback device
« Reply #11 on: 3 Apr '17 - 15:12 »
I've gotten past the crash now here's my situation:

Code: [Select]
                Bass.BASS_Init(e.Index, 44100, 0, IntPtr.Zero); // initialize the 1st output device                                             
                BASS_INFO info = new BASS_INFO();
                Bass.BASS_GetInfo(info); // get output info
                outputs[e.Index] = BassMix.BASS_Mixer_StreamCreate(info.freq, info.speakers, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_NONSTOP);
                Bass.BASS_ChannelSetAttribute(outputs[e.Index], BASSAttribute.BASS_ATTRIB_NOBUFFER, 1);
                BassMix.BASS_Mixer_StreamAddChannel(outputs[e.Index], info.speakers, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_NONSTOP);

No sound comes from my speakers even though I StreamAddChannel them.

BASS_MIXER_NONSTOP isn't a valid flag for BASS_Mixer_StreamAddChannel. Using that there will actually be setting the BASS_MIXER_PAUSE flag which has the same value, so that would explain why there would be no sound (the source is paused). BASS_STREAM_DECODE is also an invalid flag there. Please see the BASS_Mixer_StreamAddChannel documentation for a list of its valid flags.

Is there a way I can "delay" my default playback using a DSP? maybe putting a 0x00 on the first part of the buffer?

If you're using a mixer, you could use the BASS_Mixer_StreamAddChannelEx function's "start" parameter to delay the source in the mixer output.

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #12 on: 16 Apr '17 - 18:42 »
Can you show me an example of this ?

Ian @ un4seen

  • Administrator
  • Posts: 20272
Re: subclassing the default playback device
« Reply #13 on: 17 Apr '17 - 16:27 »
You could do something like this to delay a source in the mixer output:

Code: [Select]
BASS_Mixer_StreamAddChannelEx(mixer, source, 0, BASS_ChannelSeconds2Bytes(mixer, delay), 0);

Where "delay" is the wanted delay in seconds. Please see the BASS_Mixer_StreamAddChannelEx documentation for details.

gum

  • Posts: 22
Re: subclassing the default playback device
« Reply #14 on: 17 Apr '17 - 18:06 »
Code: [Select]
                Bass.BASS_Init(e.Index, 44100, 0, IntPtr.Zero); // initialize the 1st output device                                             
                BASS_INFO info = new BASS_INFO();
                Bass.BASS_GetInfo(info); // get output info
                outputs[e.Index] = BassMix.BASS_Mixer_StreamCreate(info.freq, info.speakers, 0);
                Bass.BASS_ChannelSetAttribute(outputs[e.Index], BASSAttribute.BASS_ATTRIB_NOBUFFER, 1);
                BassMix.BASS_Mixer_StreamAddChannelEx(outputs[e.Index], info.speakers, 0, Bass.BASS_ChannelSeconds2Bytes(outputs[e.Index], 5), 0);

doesn't work. no sound comes out. is this delay supposed to be on the default playback device?

Ian @ un4seen

  • Administrator
  • Posts: 20272
Re: subclassing the default playback device
« Reply #15 on: 18 Apr '17 - 13:30 »
That BASS_Mixer_StreamAddChannelEx call doesn't look quite right. I suspect it will be failing with a BASS_ERROR_HANDLE error (use BASS_ErrorGetCode to check that). The "channel" parameter should be a BASS channel handle, eg. from a BASS_StreamCreateFile call.

Note that the mixer suggestion (in my 1st reply) was to allow modifying the output from your app, not the output from all apps (in case that is what you want).