|
Wishmaster
Posts: 124
|
 |
« Reply #180 on: 4 Nov '11 - 01:49 » |
Quote
|
Hi. Thank you for your reply. Maybe it just me but, If I want to initialize all available devices in a loop Would it not be better if WASABIPROC were exported to another function Something like with BASS_ChannelSetDSP() I do not even know whether it's possible or not Var DevInfo : BASS_WASAPI_DEVICEINFO;
Device:= 0; while (BASS_WASAPI_GetDeviceInfo(Device, DevInfo) <>False) do begin if not BASS_WASAPI_Init(…) then // error
Inc(Device) End;
BASS_WASAPI_SetDevice(); BASS_WASAPI_SetProc(device : Integer; WASAPIPROC *proc,); BASS_WASAPI_Start();
Thx.
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #181 on: 4 Nov '11 - 16:24 » |
Quote
|
Is there a particular reason that you want to initialize all devices?
If you would like to be able to change the WASAPIPROC function on the fly, perhaps you could implement a wrapper function for that, ie. you pass the wrapper function to BASS_WASAPI_Init and the wrapper calls the function that you want to do the processing. You could use a single wrapper function to handle multiple devices by making use of BASS_WASAPI_GetDevice in it (to check which device the callback is dealing with), or you could use the "user" parameter to identify the device.
|
|
|
|
|
Logged
|
|
|
|
|
Wishmaster
Posts: 124
|
 |
« Reply #182 on: 15 Nov '11 - 07:49 » |
Quote
|
hi I'm writing a universal Audio Component (Delphi), and I´m try to make it as easy to use as possible! The end user must only decide which system he wants to use (WASAPI, ASIO, ...) during initialization I have the same function´s for all systems! Examplefunction Set_Device(Device : DWORD ) : Bool; begin if DS then Result:=BASS_SetDevice(Device); if ASIO then Result:= BASS_ASIO_SetDevice(Device); if WASAPI then Result:= BASS_WASAPI_SetDevice(Device); end;
I mean that's the reason for the BASS_WASAPI_SetDevice function so that you can simultaneously use multiple devices right? I have another question. BASS_ChannelPause does not work if I use WASAPI. So what is the best way to pause or stop a specific channel. Thx.
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #183 on: 15 Nov '11 - 15:02 » |
Quote
|
BASS_ChannelPause only applies to BASS playback, ie. when BASS_ChannelPlay is used. To pause a "decoding channel" (created with the BASS_STREAM_DECODE flag), you can simply stop calling BASS_ChannelGetData on it, eg. in the WASAPIPROC function. You can also use BASS_WASAPI_Stop to pause the device, and BASS_WASAPI_Start to resume it.
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #184 on: 20 Dec '11 - 17:49 » |
Quote
|
A little update is up (see the 1st post), which allows dynamic loading of BASSWASAPI, or rather dynamic unloading. Dynamically unloading BASSWASAPI could result in a crash due to there being unreleased device notification COM stuff, but that can now be avoided by calling BASS_WASAPI_SetNotify with proc=NULL prior to calling FreeLibrary (to unload BASSWASAPI).
|
|
|
|
|
Logged
|
|
|
|
|
Silhwan
Posts: 81
|
 |
« Reply #185 on: 7 Feb '12 - 08:46 » |
Quote
|
My last post - regarding the required modification of a data structure for Delphi XE2 at 64bit mode - is disappeared. The non-Delphi users may not encounter this problem by automatic 64bit alignment of address (or pointer) fields of data structure by compiler. But I had spent a few days to find out the reason of fatal error by mis-alignment of data structure at run time. Anyway I have found another problem of a WASAPI function - BASS_WASAPI_SetVolume at shared mode. I think that it is preferable that BASS_WASAPI_SetVolume should take effect only on its own session (= the program which calls BASS_WASAPI_SetVolume) at shared mode. But BASS_WASAPI_SetVolume takes effect on whole system (= end point device such as Speaker or Headphone.)
I made a component - TAudioVolume - which can control end point volume or session volume seperately, so Delphi users can use it to escape this problem.
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #186 on: 7 Feb '12 - 17:23 » |
Quote
|
My last post - regarding the required modification of a data structure for Delphi XE2 at 64bit mode - is disappeared. The non-Delphi users may not encounter this problem by automatic 64bit alignment of address (or pointer) fields of data structure by compiler. But I had spent a few days to find out the reason of fatal error by mis-alignment of data structure at run time.
Are you referring to this post? www.un4seen.com/forum/?topic=9038.msg93623#msg93623That was indeed a structure alignment issue. Unless told otherwise (eg. via a "pragma pack"), I think pretty much all C/C++ compilers will align a 64-bit pointer to an 8-byte boundary, which means there will be 4 bytes of padding inserted between the "ctype" and "name" members of the BASS_PLUGINFORM structure on a 64-bit platform. Anyway I have found another problem of a WASAPI function - BASS_WASAPI_SetVolume at shared mode. I think that it is preferable that BASS_WASAPI_SetVolume should take effect only on its own session (= the program which calls BASS_WASAPI_SetVolume) at shared mode. But BASS_WASAPI_SetVolume takes effect on whole system (= end point device such as Speaker or Headphone.)
Yes, the BASSWASAPI volume functions (eg. BASS_WASAPI_SetVolume/Mute) do indeed deal with the device/endpoint volume level rather than the session. I will look into adding a session volume control option.
|
|
|
|
|
Logged
|
|
|
|
|
Silhwan
Posts: 81
|
 |
« Reply #187 on: 7 Feb '12 - 22:22 » |
Quote
|
Oops ! Sorry, I totally forgot the correct post where I had posted.
And I have found another problem of a WASAPI function - BASS_WASAPI_SetMute. The function BASS_WASAPI_SetMute does not operate at my system (Windows 7 32bit, shared mode). I have also experenced this problem at debugging my TAudioVolume component. The mute of end point device requires a tricky code as follows, if mute then i := 0 else i := 1; // mute: Bool, i: integer AudioEndpointVolume.SetMute(BOOL(i), @GUID_TAudioVolume);
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #188 on: 8 Feb '12 - 17:13 » |
Quote
|
Another Delphi user (off forum) encountered that same problem recently. The reason for it is that Delphi's "true" is -1, while WASAPI expects "true" to be 1. I will do something for that too, at the same time as the session volume stuff.
|
|
|
|
|
Logged
|
|
|
|
|
yps
Posts: 107
|
 |
« Reply #189 on: 9 Feb '12 - 12:58 » |
Quote
|
I have added WASAPI support to the latest release of my software, and it works very well. Great job! However, some people experience the infamous BASS_ERROR_UNKNOWN on BASS_WASAPI_Init. All of them use one of the M-Audio Delta cards. The demo applications from the BASSWASAPI package seem to work fine though, so there must be something wrong in the way the cards are initialized in my code. Here's how the init section looks like: // Determine freq, chans, and flags according to configuration flags := BASS_WASAPI_AUTOFORMAT; if fMode = wmShared then begin freq := 0; chans := 0; end else begin flags := flags or BASS_WASAPI_EXCLUSIVE; freq := fSampleRate; chans := fChannels; end;
// Initialize the device CheckBassCall('BASS_WASAPI_Init', BASS_WASAPI_Init(fDeviceIndex, freq, chans, flags, fBufferSize/1000, fUpdatePeriod/1000, PlaybackWASAPIProc, self));
Any obvious mistakes here? Is there a debug version available that could help to track down the exact reason for the unknown error? By the way, are there any special requirements for the way COM was initialized for the calling thread? Or will a plain CoInitialize do?
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #190 on: 9 Feb '12 - 13:46 » |
Quote
|
Is there a debug version available that could help to track down the exact reason for the unknown error?
Yep, I'll send you a debug version to get more info. BASS_ERROR_UNKNOWN will be the result when device initialization fails for some reason that BASSWASAPI doesn't specifically check for, eg. it isn't because the device is busy or that the sample format is unsupported. By the way, are there any special requirements for the way COM was initialized for the calling thread? Or will a plain CoInitialize do?
I think that will work, but CoInitializeEx with COINIT_MULTITHREADED may be better. If COM hasn't already been initialized, then BASSWASAPI will do that itself.
|
|
|
|
|
Logged
|
|
|
|
|
yps
Posts: 107
|
 |
« Reply #191 on: 11 Feb '12 - 07:51 » |
Quote
|
With the help of a debug version Ian sent me, it turned out that the M-Audio driver expects COM to be initialized, which wasn't the case for the background thread from which BASS_WASAPI_Init was called. A simple call to CoInitializeEx just before BASS_WASAPI_Init solved the problem.
Thank you again, Ian, excellent support!
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #192 on: 13 Feb '12 - 16:01 » |
Quote
|
An update is now available in the 1st post. It adds a BASS_WASAPI_SESSIONVOL flag to have the volume related functions deal with the session volume rather than the device/endpoint volume. BASS_WASAPI_SetMute has also been updated to translate any non-0 "mute" value to 1, to get around the Delphi "true" value issue.
|
|
|
|
|
Logged
|
|
|
|
|
WACKA
Posts: 14
|
 |
« Reply #193 on: 14 Feb '12 - 11:27 » |
Quote
|
Hi Ian,
I have a small issue with basswasapi and bit depth.
When using WASAPI, what i see on my dcs gear is that all material is up sampled to 24 bit, but the frequency stays true to the origial material.. so all cd rips seem to play at 24 bit / 44.1khz with wasapi turned on.
Is there any way/flag to make sure it will output at its source depth?
N.b. I am using bass_mix for outputting the streams:
... BassMix.BASS_Mixer_StreamCreate(this.k, this.l, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_RESUME); ... BassMix.BASS_Mixer_StreamAddChannel(stream, channel, streamflags);
Best regards,
Conor
|
|
|
|
|
Logged
|
|
|
|
|
radio42
Posts: 4012
|
 |
« Reply #194 on: 14 Feb '12 - 13:03 » |
Quote
|
That depends if you are using WASAPI in Shared or Exclusive mode.
In shared mode WASAPI must use the resolution as defined in your windows sound control panel and each application will use these settings! This is true for the sample rate as well as the bit depth.
In exclusive mode you have more control over it and might define this yourself. However, for convenience, devices are always initialized (by BASSWASAPI) to use their highest sample resolution and that is then converted to 32-bit floating-point, so that WASAPIPROC callback functions and the BASS_WASAPI_PutData and BASS_WASAPI_GetData functions are always dealing with the same sample format.
As such you don't have much control over the effective bit depth being used.
In any case, WASAPI in general needs a constant format once initialized.
|
|
|
|
|
Logged
|
|
|
|
|
Ian @ un4seen
Administrator
Posts: 15276
|
 |
« Reply #195 on: 14 Feb '12 - 14:04 » |
Quote
|
By default, BASSWASAPI will use the highest resolution/bitdepth supported by the driver in exclusive mode, but it is possible to restrict that via the HIWORD of the BASS_WASAPI_Init "flags" parameter. For example, to limit it to 16-bit... BASS_WASAPI_Init(-1, 44100, 2, MAKELONG(BASS_WASAPI_EXCLUSIVE, BASS_WASAPI_FORMAT_16BIT), 0.5, 0, MyWasapiProc, NULL);
|
|
|
|
|
Logged
|
|
|
|
|
WACKA
Posts: 14
|
 |
« Reply #196 on: 14 Feb '12 - 15:08 » |
Quote
|
Thanks for the reply guys, both are really useful and just what I need
|
|
|
|
|
Logged
|
|
|
|
|
Silhwan
Posts: 81
|
 |
« Reply #197 on: 18 Feb '12 - 01:56 » |
Quote
|
The WASAPIAPI does not have a function for smooth change of volume level. I tried several times to make the function with BASS_ChannelSlideAttribute applied to mixer channel but failed. (Click noise at the end of slide operation for mute/unmute) So, I have made this unit and posted for Delphi users. // Unit WasapiVolumeSlide // // This unit slides the volume level of WASAPI, which is equivalent to BASS_ChannelSlideAttribute // with attribute BASS_ATTRIB_VOL. // This unit uses my TAudioVolume component because modified version which uses BASS_WASAPI_Set... functions // does not operate as expected. // You can get TAudioVolume component at following url, // http://www.torry.net/quicksearchd.php?String=TAudioVolume&Title=Yes // // written by Silhwan Hyun (hyunsh@hanafos.com)
unit WasapiVolumeSlide;
interface
uses Windows, Classes, Messages, {basswasapi,} AudioVolume;
const // Flags fSlideForMute = 1; // execute extra sentences for mute fSlideForUnmute = 2; // execute extra sentences for unmute fKnotifyAtEnd = 4; // post message at the end of a slide
type TWasapiSlideThread = class(TThread) private { Private declarations } ThreadTimer : HWND;
FFlags : DWORD; FMsgReceiver : hwnd; FSlideEndMsg : hwnd; FAudioVolume : TAudioVolume; FInitVolume : single; FFinalVolume : single; FStepValue : single; FMidVolume : single; procedure DoOnTimer;
protected procedure Execute; override;
public constructor Create(AudioVolume: TAudioVolume; PeriodMS: DWORD; FinalVol: single; MsgReceiver: hwnd; SlideEndMsg, Flags: DWORD); destructor Destroy; override;
end;
// The main program should create an instance of TAudioVolume prior to calling this procedure. // Mute : true on mute, false on unmute // AudioVolume : an instance of TAudioVolume // PeriodMS : the sliding period in milliseconds // MsgReceiver : handle to the message handler of main program // SlideEndMsg : message used for posting message at the end of a slide procedure WasapiSmoothMute(Mute: boolean; AudioVolume : TAudioVolume; PeriodMS: DWORD; MsgReceiver: hwnd; SlideEndMsg: DWORD);
implementation
const MaxVolume = 1.0; // Volume range : 0 ~ 1.0 StepMs = 10; // Step up/down interval = 10ms
constructor TWasapiSlideThread.Create(AudioVolume: TAudioVolume; PeriodMS: DWORD; FinalVol: single; MsgReceiver: hwnd; SlideEndMsg, Flags: DWORD); begin FreeOnTerminate := true; if FinalVol > MaxVolume then FFinalVolume := MaxVolume else if FFinalVolume < 0 then FFinalVolume := 0 else FFinalVolume := FinalVol;
ThreadTimer := CreateWaitableTimer(nil, false, 'ThreadTimer'); if ThreadTimer <> 0 then begin FAudioVolume := AudioVolume; FFlags := Flags; if (FFlags and fSlideForUnmute) = fSlideForUnmute then begin FAudioVolume.SetVolume(0); // BASS_WASAPI_SetVolume(true, 0); FAudioVolume.SetMute(False); // BASS_WASAPI_SetMute(false); end;
FInitVolume := FAudioVolume.GetVolume; // FInitVolume := BASS_WASAPI_GetVolume(true); FStepValue := (FFinalVolume - FInitVolume) / (PeriodMS / StepMS); FMidVolume := FInitVolume; FMsgReceiver := MsgReceiver; FSlideEndMsg := SlideEndMsg; end;
inherited Create(false); // starts on creation end;
destructor TWasapiSlideThread.Destroy; begin
inherited Destroy; end;
procedure TWasapiSlideThread.Execute; const _SECOND = 10000000; // 100 nanosecond intervals var qwDueTime: int64; liDueTime: _LARGE_INTEGER; begin if ThreadTimer = 0 then begin if (FFlags and fKnotifyAtEnd) = fKnotifyAtEnd then PostMessage(FMsgReceiver, FSlideEndMsg, 0{=fail}, 0); exit; end;
// Create a negative 64-bit integer that will be used to // signal the timer 1/8 seconds from now. qwDueTime := -1 * (_SECOND div 8);
// Copy the relative time into a LARGE_INTEGER. liDueTime.LowPart := DWORD(qwDueTime and $FFFFFFFF); liDueTime.HighPart := longint(qwDueTime shr 32); if SetWaitableTimer(ThreadTimer, // handle to a timer object TLargeInteger(liDueTime), // when timer will become signaled StepMS, // periodic timer interval nil, // pointer to the completion routine nil, // data passed to the completion routine false{flag for resume state}) then
repeat if WaitForSingleObject(ThreadTimer, 1000{1sec}) = WAIT_OBJECT_0 then DoOnTimer else begin if (FFlags and fKnotifyAtEnd) = fKnotifyAtEnd then PostMessage(FMsgReceiver, FSlideEndMsg, 0{=fail}, 0);
Terminate; end; until Terminated; end;
procedure TWasapiSlideThread.DoOnTimer; begin if FInitVolume = FFinalVolume then FMidVolume := FFinalVolume else FMidVolume := FMidVolume + FStepValue; if FStepValue > 0 then begin if FMidVolume > FFinalVolume then FMidVolume := FFinalVolume end else if FMidVolume < FFinalVolume then FMidVolume := FFinalVolume;
FAudioVolume.SetVolume(FMidVolume); // BASS_WASAPI_SetVolume(true, FMidVolume);
if FMidVolume = FFinalVolume then begin CancelWaitableTimer(ThreadTimer); CloseHandle (ThreadTimer); if (FFlags and fSlideForMute) = fSlideForMute then begin FAudioVolume.SetMute(true); // BASS_WASAPI_SetMute(true); FAudioVolume.SetVolume(FInitVolume); // BASS_WASAPI_SetVolume(true, FInitVolume); end; if (FFlags and fKnotifyAtEnd) = fKnotifyAtEnd then PostMessage(FMsgReceiver, FSlideEndMsg, 1{=success}, 0);
Terminate; end; end;
procedure WasapiSmoothMute(Mute: boolean; AudioVolume: TAudioVolume; PeriodMS: DWORD; MsgReceiver: hwnd; SlideEndMsg: DWORD); var WasapiSlideThread: TWasapiSlideThread; begin if Mute = AudioVolume.IsMuted then exit;
if Mute then WasapiSlideThread := TWasapiSlideThread.Create(AudioVolume, PeriodMS, 0, MsgReceiver, SlideEndMsg, fSlideForMute or fKnotifyAtEnd) else WasapiSlideThread := TWasapiSlideThread.Create(AudioVolume, PeriodMS, AudioVolume.GetVolume, MsgReceiver, SlideEndMsg, fSlideForUnmute or fKnotifyAtEnd); end;
end.
|
|
|
|
« Last Edit: 18 Feb '12 - 02:18 by Silhwan »
|
Logged
|
|
|
|
|
Subbu
Posts: 40
|
 |
« Reply #198 on: 20 Feb '12 - 05:32 » |
Quote
|
Hi Ian, I want to use BassWasApi in C# pls help me how can i do it?
|
|
|
|
|
Logged
|
|
|
|
|
radio42
Posts: 4012
|
 |
« Reply #199 on: 20 Feb '12 - 09:00 » |
Quote
|
Have you taken a look to the BASS.NET documentation - it contains various Wasapi samples? What are you exactly looking for?
|
|
|
|
|
Logged
|
|
|
|
|