HEnquist / camilladsp

A flexible cross-platform IIR and FIR engine for crossovers, room correction etc.
https://henquist.github.io/
GNU General Public License v3.0
505 stars 48 forks source link

Support for ASIO #346

Open siraaris opened 1 month ago

siraaris commented 1 month ago

Devices on Windows with more than 8 ch are presented as multiple WDM devices with 8 ch each.

In contrast the ASIO driver presents the whole channel count.

For these devices, CamillaDSP can't be used on Windows.

Would it be possible to add a build option ASIO backend?

I understand that ASIO and GPLv3 licensing does not support distribution of a binary, but a self-build option would work for people who need it.

I had a brief search for Rust ASIO libraries, some seem reasonable.

HEnquist commented 1 month ago

Devices on Windows with more than 8 ch are presented as multiple WDM devices with 8 ch each.

This is not determined by WDM, there is no 8 channel limit. The manufacturer has simply chosen to present the device like this. This is quite common (and also quite annoying). The Motu M4 for example is presented as two stereo devices.

Would it be possible to add a build option ASIO backend?

I understand that ASIO and GPLv3 licensing does not support distribution of a binary, but a self-build option would work for people who need it.

I had a brief search for Rust ASIO libraries, some seem reasonable.

ASIO has a number of problems in addition to the license. See for example here: https://www.diyaudio.com/community/threads/camilladsp-cross-platform-iir-and-fir-engine-for-crossovers-room-correction-etc.349818/post-6813205 and https://www.diyaudio.com/community/threads/camilladsp-cross-platform-iir-and-fir-engine-for-crossovers-room-correction-etc.349818/post-6264227 There are supposedly ways to work around these problems but implementing a new backend is already a lot of work without having to deal with such stuff. The only asio binding I'm aware of is the low level asio-sys that is used in the CPAL library. I don't really have the time to implement and maintain an asio backend.

Then one reasonable path I see is to use the asio support of CPAL. This would be quite straightforward since CPAL is already used by the jack backend. Unfortunately this worked very poorly last time I tried it. I'm following the development there, but asio doesn't seem to be a priority so not much happens.

siraaris commented 1 month ago

My device is a RME Digiface AVB, and inherently has a large channel count, and I use it to access a M32-DA Pro DAC which has 32 ch analog output.

I can't use CamillaDSP for this on Linux yet but am hopeful that AVB support in Pipewire will eventuate fully in the future.

On macOS I observe glitches - restarts and buffer issue that I've not managed to eliminate.

On Windows, WDM isn't an option with CamillaDSP as the 32 channels I need are presented as 4x8ch.

I've tried another convolver on Windows with ASIO and I observe very solid performance. No evidence of glitches seen on macOS.

So, I do have a workable solution, of course would prefer to use CamillaDSP.

I'll watch this issue and the repo generally if the ASIO CPAL backend becomes an option in the future!

HEnquist commented 1 month ago

On macOS I observe glitches - restarts and buffer issue that I've not managed to eliminate.

This doesn't usually happen on macOS, it's normally very reliable there. Is it easy for you to switch to macOS to run some tests? I would be interested in what the camilladsp logs say when there are problems.

HEnquist commented 1 month ago

I updated the old experimental ASIO branch to try. Things are somewhat improved since my last try, but it's not bug free and there are some quite severe limitations.

This is in the next30-asio branch here: https://github.com/HEnquist/camilladsp/tree/next30-asio

The ASIO api does not like the way that CamillaDSP accesses devices from different threads, meaning that it's only possible to use ASIO for capture or playback, not both at the same time. See the readme section here: https://github.com/HEnquist/camilladsp/tree/next30-asio?tab=readme-ov-file#experimental-asio-support

In short I don't think that this works very well currently and I'm hesitant to include it. But maybe it's still useful for someone.

siraaris commented 2 weeks ago

Thank you, and sorry, I missed this update. I've got a dev environment on Windows now, so will give this a try.

siraaris commented 2 weeks ago

On macOS I observe glitches - restarts and buffer issue that I've not managed to eliminate.

This doesn't usually happen on macOS, it's normally very reliable there. Is it easy for you to switch to macOS to run some tests? I would be interested in what the camilladsp logs say when there are problems.

I have to setup my laptop a bit, but shouldn't be difficult. Will send logs over.

siraaris commented 2 weeks ago

Compiled next30-asio branch, including the dependency requirements. I modified the .YML file from the version I was using on macOS, and get the following - seems to be stuck on a particular filter (KS-T).

camilladsp-asio-log.txt

siraaris commented 2 weeks ago

Config file attached. cexe.yml.txt

siraaris commented 2 weeks ago

Ok, this is very weird. After navigating to the directory where the filter files are (File Explorer), and started CamillaDSP again, it works (or at least progresses) further now. I really don't understand why this would be happen, but happy that things are progressing, but still weird.

... actually no. Restarted camilladsp, and now get this error:

memory allocation of 1248 bytes failed

Confused.

siraaris commented 2 weeks ago

Another error:

fatal runtime error: Rust cannot catch foreign exceptions

Something is definitely not right.

Attaching another trace when it starts, but something's not right with the rate (I've set it to 96k but reporting 16k, 48k etc).

[Uploading camilladsp-asio-log-sort-of-working.txt…]()

siraaris commented 2 weeks ago

Thanks for creating the branch! That was fun. Tantalisingly close, but not quite :-)

siraaris commented 2 weeks ago

I should have read the readme sorry, clearly I need to use a virtual device not capture and playback on the same.

HEnquist commented 2 weeks ago

I should have read the readme sorry, clearly I need to use a virtual device not capture and playback on the same.

Yeah this is a pretty significant limitation, and it's really not an easy one to get around. Capture and playback needs to be done in the same thread, not separate threads like camilladsp does it now (which works fine for all the other audio APIs).

siraaris commented 2 weeks ago

I used a Windows loopback program (https://www.nerds.de/en/loopbeaudio.html) to handle 2ch input via Roon to bring into Camilla as a 2ch (Wasapi) capture, and using Asio as the (32ch) playback.

Now the app runs, and processes but I notice:

Both of these are weird as the rate is fixed in Windows sound control panel and Roon resamples to the chosen rate (96khz).

Hope the logs provide some indication of what's going on or potential hint at ways to fix.

camilla-asio-wasapi.log.txt

HEnquist commented 2 weeks ago

This is a problem:

Processing load: 613.6589%

This basically means that the CPU is overloaded by more than 6x. I see you have a lot of FIR filters, but not so many that I would expect that huge load. The reason is probably that you are using an unusual chunksize of 19200. Try with a power of two instead, for example 16384. That should make the convolution run much faster.

siraaris commented 2 weeks ago

I've tried with setting the chunk size to 16k. I'm not sure that the reported Processing load is overly meaningful as when watching Performance Monitor it was well under 10% when Camilla was reporting 613% - weird.

I also tried a different WDM based Loopback (VAC, https://vac.muzychenko.net/en/) which seems to be better behaved compared to the nerds.de one. If the chunksize is 16k, I don't get wasapi errors.

But regardless - I still get timeouts/restarts from the ASIO playback.

Interestingly another (commercial) Windows convolver provides a virtual ASIO driver as an option to get audio into the convolver, and then the capture is taken from the virtual ASIO driver mirror of whatever's played into it.

That might be a way (in the future perhaps) to consider - would then enable multithreaded capture and playback?

HEnquist commented 2 weeks ago

I've tried with setting the chunk size to 16k. I'm not sure that the reported Processing load is overly meaningful as when watching Performance Monitor it was well under 10% when Camilla was reporting 613% - weird.

100% in Performance Monitor means that all all cores are fully utilised. If a single core on for example an 8-core machine is maxed out you will see 12.5 %. CamillaDSP simply measures how long it takes to process a chunk and compares with the duration of a chunk. Over 100% means it cannot keep up since processing runs slower than real time. What CPU did you try this on?

I also tried a different WDM based Loopback (VAC, https://vac.muzychenko.net/en/) which seems to be better behaved compared to the nerds.de one. If the chunksize is 16k, I don't get wasapi errors.

Good tip, thanks!

But regardless - I still get timeouts/restarts from the ASIO playback.

Interestingly another (commercial) Windows convolver provides a virtual ASIO driver as an option to get audio into the convolver, and then the capture is taken from the virtual ASIO driver mirror of whatever's played into it.

That might be a way (in the future perhaps) to consider - would then enable multithreaded capture and playback?

That would be possible yes, in theory at least. There are also issues with the ASIO SDK license. It's very restrictive and doesn't fit well in open source projects. This means my motivation for working with it is quite low unfortunately.

siraaris commented 2 weeks ago

Ok, I'll tinker with Wasapi capture and Asio playback a bit more and see what I find.

siraaris commented 1 week ago

Not much to report. I downloaded and tried out VB-Cable, no real difference to VAC though.

If logs are of interest please let me know and I'll run a trace and attach.

HEnquist commented 1 week ago

Does it run reliably with a lightweight config? For example if you keep only the mixer(s) in the pipeline but remove all filters.

siraaris commented 1 week ago

Yes, with no filters it runs stable. Attaching three configs and log scenarios:

01 - Config with no filters, just mixers - stable, clearly signal is presented to DAC (ie TotalMix reports signal on all 32 ch in use).

02 - Config with Gain and Delay added to 1st-stage mixer (2 in, 18 out). Looks like filtering loops quite a few times, adding each to the whole set? Could just be logging. Rate is observed as set (96khz). However no signal is presented to DAC on any channels.

03 - Config with only FIR filters enabled on the 2nd-stage mixer (18 in, 32 out). Same looping of filters, plus a bunch of logs "Dropping captured chunk XXX with len 7680". Samplerate is not presented as configured.

01_YML_3sb-plain-mixer.txt 01_LOG_camilla-asio-plain-mixer.txt

02_YML_3sb-gain+delay.txt 02_LOG_camilla-asio-gain+delay.txt

03_YML_3sb-fir.txt 03_LOG_camilla-asio-fir.txt

siraaris commented 1 week ago

Well, good news - with a simplified configuration file, using the aggregated pipeline Filter groupings, it works!

working-cexe-asio-logfile.txt

working-cexe-asio-yaml.txt

HEnquist commented 1 week ago

using the aggregated pipeline Filter groupings

Ah that explains it! There is a bug, the old "channel" property on filter steps has been removed. It's supposed to give an error if the config has it, but that is missing. The result then is that it ignores the "channel" property. And when "channels" (with the s) is missing that means apply to all channels. So all filters got applied to all channels, no wonder it got a bit heavy..

I'll fix the bug asap.

siraaris commented 1 week ago

I've been running now for a few hours. Any plans to include ASIO support into next30?

HEnquist commented 1 week ago

I'm not planning to include it in the next release, there are too many problems with it. But I'll update the asio branch to have all the new things from next30.

siraaris commented 1 week ago

Thank you! I can probably track if you decide to leave it u til next40. I'll submit any issue I find :)

siraaris commented 1 week ago

By the way, when I enabled (just for kicks) the FFTW feature, camilladsp.exe just exits, with no errors even with -vv Seems weird, although I am not going to use the feature, RustFFT is fine.

Also, how do I stop camilladsp.exe exiting in a PowerShell session when I disconnect from a Remote Desktop session?

HEnquist commented 1 week ago

Just tried the FFTW feature on an arm windows system, and there it doesn't build at all. The FFTW rust binding depends on some very outdated libraries and it doesn't look like it's likely to be fixed anytime soon. I'll just remove it.

I don't know about remote desktop, but could it be related to this? There are some suggestions on the last page. https://answers.microsoft.com/en-us/windows/forum/windows8_1-networking/remote-desktop-connection-does-not-leave-programs/f29719e9-64d2-4614-b66c-2363511a9293?page=1

siraaris commented 1 week ago

It's weird. If I have another process eg more file.yml, and disconnect RDP and reconnect that process remains. It's only camilladsp.exe that dies. Almost like RDP disconnect sends a signal to the process.

Actually I maybe think it's to do with the audio Loopback device being removed with RDP disconnect.

siraaris commented 1 week ago

Logs:

2024-06-27 16:39:57.228136 TRACE [src\wasapidevice.rs:493] capturing 2024-06-27 16:39:57.228147 TRACE [src\wasapidevice.rs:1068] got chunk, length 7680 bytes 2024-06-27 16:39:57.228179 TRACE [src\wasapidevice.rs:1065] capture device needs more samples to make chunk, reading from channel 2024-06-27 16:39:57.239172 TRACE [src\wasapidevice.rs:527] Available frames from capture dev: 960 2024-06-27 16:39:57.239217 TRACE [C:\Users\Aris Theocharides.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasapi-0.15.0\src\api.rs:1165] read 960 frames 2024-06-27 16:39:57.239232 TRACE [src\wasapidevice.rs:493] capturing 2024-06-27 16:39:57.239248 TRACE [src\wasapidevice.rs:1068] got chunk, length 7680 bytes 2024-06-27 16:39:57.239303 TRACE [src\wasapidevice.rs:1065] capture device needs more samples to make chunk, reading from channel 2024-06-27 16:39:57.249501 TRACE [src\wasapidevice.rs:527] Available frames from capture dev: 960 2024-06-27 16:39:57.249543 TRACE [C:\Users\Aris Theocharides.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasapi-0.15.0\src\api.rs:1165] read 960 frames 2024-06-27 16:39:57.249556 TRACE [src\wasapidevice.rs:493] capturing 2024-06-27 16:39:57.249573 TRACE [src\wasapidevice.rs:1068] got chunk, length 7680 bytes 2024-06-27 16:39:57.249612 TRACE [src\wasapidevice.rs:1065] capture device needs more samples to make chunk, reading from channel 2024-06-27 16:39:57.260396 TRACE [src\wasapidevice.rs:527] Available frames from capture dev: 960 2024-06-27 16:39:57.260431 TRACE [C:\Users\Aris Theocharides.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasapi-0.15.0\src\api.rs:1165] read 960 frames 2024-06-27 16:39:57.260439 DEBUG [src\wasapidevice.rs:553] Captured a buffer marked as silent 2024-06-27 16:39:57.260450 TRACE [src\wasapidevice.rs:493] capturing 2024-06-27 16:39:57.260492 TRACE [src\wasapidevice.rs:1068] got chunk, length 7680 bytes 2024-06-27 16:39:57.260523 TRACE [src\wasapidevice.rs:1065] capture device needs more samples to make chunk, reading from channel 2024-06-27 16:39:57.266040 TRACE [src\wasapidevice.rs:527] Available frames from capture dev: 960 2024-06-27 16:39:57.266071 TRACE [C:\Users\Aris Theocharides.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasapi-0.15.0\src\api.rs:1165] read 960 frames 2024-06-27 16:39:57.266078 DEBUG [src\wasapidevice.rs:553] Captured a buffer marked as silent 2024-06-27 16:39:57.266103 TRACE [src\wasapidevice.rs:493] capturing 2024-06-27 16:39:57.266114 TRACE [src\wasapidevice.rs:1068] got chunk, length 7680 bytes 2024-06-27 16:39:57.266149 TRACE [src\wasapidevice.rs:1065] capture device needs more samples to make chunk, reading from channel 2024-06-27 16:39:57.287222 TRACE [C:\Users\Aris Theocharides.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasapi-0.15.0\src\events.rs:157] state change to: Inactive 2024-06-27 16:39:57.297598 TRACE [C:\Users\Aris Theocharides.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasapi-0.15.0\src\events.rs:174] Disconnected 2024-06-27 16:39:57.297629 DEBUG [src\wasapidevice.rs:460] Capture disconnected, reason: SessionDisconnected 2024-06-27 16:39:57.297853 ERROR [src\wasapidevice.rs:1093] Channel is closed 2024-06-27 16:39:57.297884 DEBUG [src\wasapidevice.rs:878] Send CaptureError 2024-06-27 16:39:57.297887 TRACE [src\processing.rs:34] AudioMessage::EndOfStream received 2024-06-27 16:39:57.297946 ERROR [src/bin.rs:316] Capture error: receiving on an empty and disconnected channel 2024-06-27 16:39:57.302042 DEBUG [src/bin.rs:321] Wait for playback thread to exit.. 2024-06-27 16:39:57.576687 TRACE [src/bin.rs:330] All threads stopped, returning 2024-06-27 16:39:57.576791 DEBUG [src/bin.rs:1136] Processing ended with status Ok(Restart) aris@CONTROLLER:~$

siraaris commented 1 week ago

Ok, known issue.

https://vac.muzychenko.net/en/manual/compat.htm#:~:text=To%20access%20Virtual%20Cable%20devices,the%20Remote%20Desktop%20connection%20dialog.