dechamps / FlexASIO

A flexible universal ASIO driver that uses the PortAudio sound I/O library. Supports WASAPI (shared and exclusive), KS, DirectSound and MME.
Other
1.4k stars 76 forks source link

Listing channels from all devices #45

Open akankshaaK opened 5 years ago

akankshaaK commented 5 years ago

not able to build the code, please help me with all the build steps to generate .exe file

dechamps commented 5 years ago

I just noticed that FlexASIO fails to build with VS2019 due to a C28204 error. I fixed it in e07e8c0efb7f0407a8613d9c79aa98c7592ea233, so make sure you have the latest master.

The easiest way to build FlexASIO from scratch is:

  1. Install Visual Studio 2019. (2017 should work too, as long as it's up to date, but the menus are different. 2019 is more straightforward.) Make sure to include the C++ workflow component including CMake and git.
  2. Open Visual Studio.
  3. On the start-up screen, select "Clone or check out code".
  4. Enter https://github.com/dechamps/FlexASIO.git, hit "Clone".
  5. Once cloning is complete and CMake generation is finished, click "Install flexasio" in the "Build" menu.
  6. Wait for the build to complete. The build output will show you the paths where you can find the resulting binaries.
dechamps commented 5 years ago

In an offline email thread you mentioned that you were trying to build from a zip file of the source code. I'm afraid that's not going to work, because the build system (specifically CMakeUtils/version.cmake) expects to be able to use git to extract version information from the source tree.

I would suggest building from an actual git repository. If that's not an option, feel free to hack version.cmake to skip the git part (e.g. setting DECHAMPS_CMAKEUTILS_GIT_DESCRIPTION and DECHAMPS_CMAKEUTILS_GIT_DESCRIPTION_DIRTY to something like "unknown" instead of running git). I would also accept a clean patch that does this if it detects that it's running outside of a git repository.

dechamps commented 5 years ago

On second thought, I'm not entirely sure that would cause the entire build to fail - a failure of execute_process should not crash the build.

You mentioned you're getting the following error:

MSB6006- “cmd.exe” exited with code 1.

Can you provide the full log? This line alone provides almost no information.

akankshaaK commented 5 years ago

Thanks for all the help. I have one more query- if i want to list down all the devices connected in the Active input channel/Active output channel, would it be possible without control panel or changing in the configuration file. And yes, I want to list down the names of devices and not the IN 0+1 or OUT 0+1 in the Active input channel/Active output channel.

dechamps commented 5 years ago

I'm not sure I understand what you're trying to do. I'm going to assume that instead of, say, "IN 0", you want the channel name to be something like "IN 0 My Audio Device" or something like that.

In and of itself, that would be a fairly trivial code change. FlexASIO::inputDevice and FlexASIO::outputDevice contain the names of the input and output devices. You can use that in FlexASIO::GetChannelInfo() to add the device name to the channel name. I would even probably accept a patch that does that, as that indeed sounds useful.

There are just two things you might want to be aware of:

akankshaaK commented 5 years ago

"The maximum size of a channel name is 31 characters. That's an ASIO limitation. See page 19 of the ASIO SDK documentation. Long device names might need to be truncated."

Yes, this is where i was stuck at, now that i have truncated the name and copied it to ASIOChannelInfo but only one device name is being shown.

Now to list down all the connected devices, do i have to write another patch for GetAllChannelInfo in the flexasio.cpp or is there any other way to do it?

dechamps commented 5 years ago

Oh. So what you want to do is list all channels from all devices, not just the active one?

Well, in that case, just listing the channels is easy (get the device list from PortAudio, enumerate the channels, done), but I'm guessing you don't want to just list them of course, you want to actually be able to use these channels. That's not as easy, because the current code structure assumes that FlexASIO knows which input and output devices it's going to use as early as ASIO driver initialization. Now, you could definitely change that to decide device input and output devices at ASIO createBuffers time (i.e. inputDevice and outputDevice would be instantiated at FlexASIO::PreparedState construction, as opposed to FlexASIO construction). This way, you can decide to initialize the input and output devices after the host application has decided which channels it's going to use (which happens at createBuffers time).

However, there are a few caveats to that approach. First, sample rate enumeration is going to be awkward, because that happens before createBuffers, and FlexASIO can't know what sample rates are valid if it doesn't know what devices it's going to use. Second, and most importantly, FlexASIO still expects there to be only one streaming input device and one streaming output device at any given time. Which means that you wouldn't be able to select, say, channel 3 from input device A and channel 1 from input device B simultaneously. The reason for that limitation is because a single PortAudio stream can only have up to one input device and up to one output device, not more. (There is one exception: the MME backend in PortAudio has a special mode where it can use many devices simultaneously. That would only work for MME, though.)

Now, you could get around that limitation by opening multiple PortAudio streams at the same time. But now you have to synchronize the various buffers from these streams with each other (buffer adaptation), which gets really complicated and has latency implications. Not to mention that, in general, it won't work reliably with devices that use different clocks, for fundamental reasons that have more to do with hardware than with software. You could work around it by doing sample rate adjustment on the fly, but that is vastly more complicated than just buffer adaptation.

So, to summarize:

akankshaaK commented 5 years ago

Okay. So all the alternate solutions that you've suggested for all the problems will create more problems or it will be quite difficult to implement it?

Yes, we can not use MME as latency is high for this host. So at what time, buffer synchronization should be done for multiple streams. And i did not get the clock scenario. Even if the device clocks are not same, can't we make it default or something during buffer initialization.

And what my requirement is - that all the devices which are connected to the system should be listed down and from that list i can select and deselect the devices to use it accordingly.

Now In ASIO4ALL, there is a control panel to do that for multiple devices. Is it possible to implement my requirement using control panel without any of your mentioned difficulties?

dechamps commented 5 years ago

So all the alternate solutions that you've suggested for all the problems will create more problems or it will be quite difficult to implement it?

Basically, yes.

So at what time, buffer synchronization should be done for multiple streams.

I don't understand the question. To rephrase what I said: if you want to use multiple input devices or multiple output devices at the same time, you either need to use MME or you need to instantiate multiple PortAudio streams. If you have multiple PortAudio streams, you need to synchronize buffers. Which is doable, but far from trivial, and might have latency implications.

And i did not get the clock scenario.

If you want to use multiple audio devices that are not backed by the same hardware (for example: two different USB audio interfaces), then it's likely that these devices won't be using the same hardware clock. Which means they will be running at very slightly different speeds. But an ASIO driver can only run at a single speed. If you choose to make the driver run at the speed of device A, then device B will slowly drift over time. Because of this, at some point, the buffer in device B will either become empty (underrun) or too full (overflow) and you will get an audible discontinuity (glitch). How long you can run the stream before a glitch occurs is difficult to know in advance because it depends on the buffer size and the hardware. I would consider myself lucky if it happens less than once a minute or so.

This is a fundamental problem that is not specific to FlexASIO. It affects any software solution that wants to use multiple audio devices at the same time, including ASIO4ALL for example. The only way to get around it is to resample the audio to slightly alter its speed, adapting it to the speed of each device. Which, again, is doable, but is really hard to implement correctly, especially if you add latency constraints on top of that.

Even if the device clocks are not same, can't we make it default or something during buffer initialization.

I don't understand what you mean by this.

Now In ASIO4ALL, there is a control panel to do that for multiple devices.

Yes. That just means the developer of ASIO4ALL decided to spend the time and effort to implement this feature. They likely had to design and write buffer adaptation logic to make that happen (although perhaps the WDM-KS API, which is what ASIO4ALL uses, makes this easier, I don't know).

Is it possible to implement my requirement using control panel without any of your mentioned difficulties?

No. It doesn't matter if the channels are selected in the ASIO channel list, in a control panel, in a configuration file, or somewhere else. The problems I'm describing are backend problems, not frontend problems. User interface is the easy part.

akankshaaK commented 5 years ago

Kindly provide one sample configuration file (FlexASIO.toml) if possible as i want to change the default device to one specified device using configuration file.

dechamps commented 5 years ago

This is already explained in the documentation, and it includes an example that changes the output device. You'll want to run PortAudioDevices to figure out which names you can use.

akankshaaK commented 5 years ago

yes, from the CONFIGURATION.md, i created one FlexASIO.toml file and provided the details from the example. But it is not able to parse the .toml file. So, maybe the format that i have provided is not correct but it is just like the example that you have provided.

dechamps commented 5 years ago

It would help if you could provide a log that shows the error.

akankshaaK commented 5 years ago

FlexASIO.zip

this attachment is the FlexASIO.toml file that i am using, it is getting parsed successfully but at the application end when i am using the FlexASIO, it is saying - "Error when trying to open audio device! Can't create i/o buffers."

I have tried for all backends and with different devices (including default backend and default devices), but for all, the error is same.

dechamps commented 5 years ago

You're trying to open a stereo output device with 6 channels. That doesn't make a ton of sense, and is likely to be the cause of the problem (especially when using WASAPI Shared, which requires matching channel counts). I can't say for sure, though, because you did not provide a log.

In general, these kinds of failures are much easier to troubleshoot by looking at the log, because most ASIO applications do not provide all the error details from the underlying driver.

akankshaaK commented 5 years ago

I have setup the build environment for the flexASIO in other system but i am encountering this cmake error-

Severity Code Description Project File Line Suppression State Error CMake Error at C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-3.14/Modules/CMakeTestCCompiler.cmake:60 (message): The C compiler

"C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.21.27702/bin/HostX64/x64/cl.exe"

is not able to compile a simple test program.

It fails with the following output:

Change Dir: C:/Users/akankshaak/Desktop/new_1/src/out/build/x64-Debug/CMakeFiles/CMakeTmp

Run Build Command(s):C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe cmTC_f5b0f 
[1/2] Building C object CMakeFiles\cmTC_f5b0f.dir\testCCompiler.c.obj
[2/2] Linking C executable cmTC_f5b0f.exe
FAILED: cmTC_f5b0f.exe 
cmd.exe /C "cd . && "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E vs_link_exe --intdir=CMakeFiles\cmTC_f5b0f.dir --rc=rc --mt=CMAKE_MT-NOTFOUND --manifests  -- C:\PROGRA~2\MICROS~3\2019\PROFES~1\VC\Tools\MSVC\1421~1.277\bin\Hostx64\x64\link.exe /nologo CMakeFiles\cmTC_f5b0f.dir\testCCompiler.c.obj  /out:cmTC_f5b0f.exe /implib:cmTC_f5b0f.lib /pdb:cmTC_f5b0f.pdb /version:0.0  /machine:x64  /debug /INCREMENTAL /subsystem:console  kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
RC Pass 1: command "rc /foCMakeFiles\cmTC_f5b0f.dir/manifest.res CMakeFiles\cmTC_f5b0f.dir/manifest.rc" failed (exit code 0) with the following output:
The system cannot find the file specified
ninja: build stopped: subcommand failed.

CMake will not be able to correctly generate this project. C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/share/cmake-3.14/Modules/CMakeTestCCompiler.cmake 60

Can you please suggest something for this?

dechamps commented 5 years ago

In the future, please file separate issues for separate problems. Your build issues are not related to your original request regarding channel routing.

Looking at your log I doubt your problem has anything to do with FlexASIO; it looks like an issue with your Visual Studio installation. By doing a quick Google search for RC Pass 1 The system cannot find the file specified, I found the following:

https://developercommunity.visualstudio.com/content/problem/401228/visual-studio-not-able-to-compile-a-simple-hello-w.html

https://gitlab.kitware.com/cmake/cmake/issues/18920

It seems to be some kind of incompatibility between some versions of Visual Studio and WDK. There are a few workarounds suggested at the bottom of that last thread; you might want to try them.

akankshaaK commented 5 years ago

I have too many WDKs with visual studio but none of them seems to be working.

Windows version- Windows 10 pro version 10.0.1734 Visual studio 2019 version 16.1.3 with Windows 10 SDK 10.0.17763.0 Following are the WDK installed - WDK 10.0.17134.1 WDK 10.0.17763.1 WDK 10.0.18362.1 Windows SDK installed - Windows SDK 10.1.10586.212 Windows SDK 10.1.16299.15 Windows SDK 10.1.17763.132 Windows SDK 10.1.18362.1

Please suggest something to resolve this error and kindly tell which WDK and visual studio version you are using for the same.

dechamps commented 5 years ago

I can build the latest master just fine using Visual Studio 16.0.2 (VC 14.20.27508), WDK 10.0.18362.0.

After upgrading to Visual Studio 16.1.3 (VC 14.21.27702), same WDK version, still works.

This is with the default configuration (x64-debug), from clean working copy and cache directories.

I don't know why it doesn't work for you. I would suggest perhaps uninstalling all SDK versions except 18362.