Coder Social home page Coder Social logo

dechamps / asio401 Goto Github PK

View Code? Open in Web Editor NEW
6.0 6.0 2.0 701 KB

An unofficial ASIO driver for the QuantAsylum QA403, QA402 and QA401 audio analyzers.

License: Other

CMake 8.63% C++ 89.93% C 0.27% Inno Setup 1.17%
audio audio-plugin asio asio-drivers c-plus-plus windows usb usb-devices

asio401's Introduction

Etienne Dechamps

Also known as: dechamps, edechamps, e-t172

I am a software engineer with ~20 years experience (~10 years professionally) specializing in backend/systems programming targetting Linux and Windows. I also like to spend my time on pet projects related to audio and video playback (e.g. calibration, signal processing), and a bunch of other things.

My primary language is C++, but I also dabble in Python especially for data crunching and signal processing projects. I'd love to write some Rust one day.

This is my personal profile describing projects I do on my free time. I am also employed as a software engineer by Google, but none of the activity under this GitHub profile is affiliated to my employer in any way. My GitHub activity on behalf of my employer can be found under the edechamps-Google profile.

Active projects

  • FlexASIO, a universal ASIO driver (C++, Windows, audio)
    • By far the project I'm most known for, with 1k+ GitHub stars and a Wikipedia mention.
  • ASIO401, an ASIO driver for the QA403 industrial-grade audio analyzer and earlier versions (C++, Windows, USB, audio)
    • Directly implementing a bespoke USB protocol using WinUSB.
    • Developed with the support and blessing of the manufacturer.
  • videojitter, a physical light-based video frame presentation timing measurement system (Python, video, signal processing)
    • The first tool of its kind, as far as I'm aware.

Inactive projects

  • Loudspeaker Explorer, a loudspeaker measurement visualization, analysis and comparison tool (Python, Jupyter, data visualization, audio)
    • Ever wondered what would happen if someone crammed an entire app into a single Jupyter notebook and ran the entire thing off Colab? Now you know.
  • RudeWindowFixer, a tool to fix Windows always-on-top taskbar issues (C, Windows, binary reverse engineering)
    • My first foray into binary reverse engineering, reversing closed-source Windows explorer binaries related to taskbar operation and using my findings to work around a particularly annoying bug Microsoft hasn't bothered to fix in many years.
  • WindowInvestigator, a set of Windows window management introspection tools (C, Windows)
    • I wrote these to help with the investigation that led to RudeWindowFixer.
  • WinSoftVol, a Windows driver to force software volume control (C, Windows, kernel-mode driver)
    • My first foray into Windows driver development.
    • This trivial filter driver alters the way Windows audio devices work, preventing Windows from using hardware volume control.
  • kmlpipe, a geographic data processing toolbox (bash, XSLT, GIS)
    • I wrote this to assist me in my search for the perfect London flat.
    • It's a geographical information system using XML files as its internal representation (I'm sorry), with individual processing steps written in XSLT (I'm very sorry), with the whole thing orchestrated by a pile of shell scripts (I am so, so sorry). It also integrates with various APIs like Google Maps.
      • Needless to say, if you're planning to use this, you are either very brave, foolish, or both.
  • AudioMeterEvent, a tool to automatically call an HTTP API when a Windows audio device is in use (C#, Windows, audio)
    • My first foray into C#.
    • I use this for home automation, to automatically turn my speakers on/off based on audio activity.
  • LGTVDeviceListener, an LG TV remote control tool triggered by Windows USB device plug/unplug events (C++, Windows)
    • What do you mean, "niche"?
  • laplock, a tool to automatically lock a Windows laptop when its lid is closed (C, Windows)
    • One of these "I can't believe Windows doesn't have that built in" workarounds
    • My oldest project on GitHub: initial release was in 2013. It still works and I still use it to this day!
  • APO, a bunch of random docs on Windows APOs (Windows, audio)
  • audiotools, a disparate set of docs and tools for audio measurement (audio)
    • Includes discussions of some of the relevant IEC and AES standards.
  • HDRCompare, a set of filters to compare SDR vs. HDR video files (ffmpeg, video)
  • WinIPBroadcast, a tool to send network broadcasts to all Windows network interfaces (C, Windows, networking)
    • Another decade-old tool, which (as far as I know) still works to this day.
    • I wrote it to get old LAN games to work. Not nearly as useful nowadays.

Projects I've significantly contributed to

  • tinc, a peer-to-peer mesh VPN (C, networking)
    • Made major contributions to the modern tinc 1.1 protocol (SPTPS), including redesigning the way it does NAT traversal (UDP hole punching, etc.) and MTU probing.
  • ZFS On Linux, a feature-rich filesystem (C, Linux, kernel)
    • My first foray into Linux kernel development.
    • Made a number of non-trivial contributions, mostly related to performance and scalability, on behalf of my employer at the time, OVH.

asio401's People

Contributors

dechamps avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

asio401's Issues

"mutex destroyed while busy" when stopping ASIOTest

Just got this once:

2019-01-23T20:08:34.4659475-00:00 16808 15816 bufferSwitchTimeInfo(params = (ASIO time with reserved 0 0 0 0, time info (ASIO time info with speed 0, system time 802573166000000, sample position 0, sample rate 48000 Hz, flags 7 [kSystemTimeValid, kSamplePositionValid, kSampleRateValid], reserved 0 0 0 0 0 0 0 0 0 0 0 0), time code (ASIO time code with speed 0, samples 0, flags 0, future 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)), doubleBufferIndex = 0, directProcess = 1)
2019-01-23T20:08:34.4668960-00:00 16808 15816 ASIOGetSamplePosition()
2019-01-23T20:08:34.4676852-00:00 16808 15816 -> 0 [ASE_OK]
2019-01-23T20:08:34.4678572-00:00 16808 15816 Sample position: 0 timestamp: 0
2019-01-23T20:08:34.4680116-00:00 16808 15816 ASIOOutputReady()
2019-01-23T20:08:34.4683469-00:00 16808 15816 -> -1000 [ASE_NotPresent]
2019-01-23T20:08:34.4685409-00:00 16808 15816 Buffer switch count: 469/469
2019-01-23T20:08:34.4687069-00:00 16808 15816 <- nullptr
2019-01-23T20:08:34.4687617-00:00 16808 12064
2019-01-23T20:08:34.4689738-00:00 16808 12064 ASIOStop()
d:\agent\_work\3\s\src\vctools\crt\crtw32\stdcpp\thr\mutex.c(51): mutex destroyed while busy

This after hitting CTRL+C in ASIO401Test. It doesn't seem easy to reproduce.

ASIO401 does not report sample position and timestamp correctly

Looks like sample position and timestamp are broken in latest master:

2019-01-22T18:28:05.7496894-00:00 13584 9824 Updated position: 4096 samples
2019-01-22T18:28:05.7497665-00:00 13584 9824 Updated current timestamp: 710144449000000
2019-01-22T18:28:05.5795064-00:00 13584 9824 Firing ASIO bufferSwitchTimeInfo() callback with buffer index: 1, time info: (ASIO time with reserved 0 0 0 0, time info (ASIO time info with speed 0, system time 710144279000000, sample position 0, sample rate 48000 Hz, flags 7 [kSystemTimeValid, kSamplePositionValid, kSampleRateValid], reserved 0 0 0 0 0 0 0 0 0 0 0 0), time code (ASIO time code with speed 0, samples 0, flags 0, future 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
2019-01-22T18:28:05.5813555-00:00 13584 9824 --- ENTERING CONTEXT: getSamplePosition()
2019-01-22T18:28:05.5815107-00:00 13584 9824 Returning: sample position 0, timestamp 0
2019-01-22T18:28:05.5816607-00:00 13584 9824 --- EXITING CONTEXT: getSamplePosition() [OK]

ASIO401 should support write-only mode for large buffer sizes

Currently, ASIO401 always reads from the QA401, even if no input channels are enabled on the ASIO side.

For small buffer sizes this makes sense, because read pushback is the only signal ASIO401 can use to determine what the output queue watermark is - the alternative would be to keep the output queue filled, which would increase output latency.

However, for large buffer sizes that equal or exceed the hardware output queue size, the QA401 will push back on writes anyway, so we don't need to use read pushback as a signal, therefore we could simply not read at all in this configuration.

The advantage of not issuing reads is that it makes the pipeline more efficient (in particular it uses less USB bandwidth) and therefore reduces the risk of missing deadlines.

Stream exhibits DC offset if the previous stream ended abruptly

During a loopback test, I noticed that if the previous stream ended abruptly (i.e. process terminated), then the beginning of the next stream will show a large DC offset. What's even more eyebrow-raising is that the DC offset progressively fades away, but it takes a long time for it to do so (multiple seconds) - it looks like the slow discharge of some large capacitor.

I did not yet check if it's the output side that's generating the DC offset or if it's the input side that's adding it.

ASIO401 crashes if methods are called on an uninitialized driver

CASIO401::EnterInitialized() checks that the driver is initialized before handling a driver method call. The problem is, if the check fails, EnterInitialized() throws a C++ exception (without a catch) instead of returning an ASIO error code. This will likely crash the entire host process.

This bug was discovered when troubleshooting an issue with the HpW Works software. In practice it's benign because the crash can only occur if an application is misusing the driver, which should not happen in the first place.

Newly started stream begins with last 64 samples of previous stream

While doing a loopback test, I noticed that the beginning of the first input block contains what looks like the last 64 samples of the previous stream - basically the remnants of the last stream appear to be leaking into the next stream.

This happens even if the previous stream ended gracefully, and despite the fact that ASIO401 follows the QA401 reset procedure after a stream ends and before the next one starts.

I did not yet check if it's the output side or the input side that's at fault here.

ASIO401 doesn't work if no output channels are specified

In current master, if no output channels are specified, ASIO401 never starts the QA401 and never reads anything. The host application will only get silence.

While investigating this I also noticed that the approach of skipping the writes if no output channels are specified doesn't seem to work - if I try, the first read blocks forever. In other words, it looks like the QA401 doesn't support read-only mode (although write-only does work). One implication of this is that writing 5 into register 4 is not the the only thing that's required for the QA401 to start streaming - there needs to be data in the output queue, as well.

ADC noise floor takes 20+ seconds to stabilize when attenuator is off

With ASIO401 1.1, attenuator = false, and the QA401 inputs shorted, the following command:

ASIO401Test --record-to-file noisefloor.wav --buffer-switch-count 1600

Records a file whose amplitude over time looks like the following (left and right channel):

qa401nf1
qa401nf2

With the attenuator enabled the issue is still there, but much less pronounced (converges in about 1 second).

This is especially problematic for THD+N measurements, which suffer from an elevated noise floor if done too early after streaming starts.

ASIO401 is Windows only

ASIO401 would be much more useful if it would expose the QA40x devices as USB Audio Devices to Linux or Mac OS X.

First ~20 ms of playback is highly distorted

When measuring the output of ASIO401 a4144b7 (default settings) playing a sweep with an oscilloscope, this is how the beginning of the stream looks like:

qa401start

The first ~20 ms (which, perhaps coincidentally, is about the size of the QA401 hardware queue) is distorted.

This doesn't seem related to something happening in the previous stream as I can reproduce it even when the previous stream was just a bunch of silence.

stop() should unblock output ready

ASIO401 suffers from the same issue as dechamps/FlexASIO#235, where an application that calls stop() without calling outputReady() for the last bufferSwitch() will cause the driver to hang.

This notably affects the Cycling 74' Max 8 application, which I would expect to be unusable with ASIO401 2.0.

Polarity of the signal is reversed

Over at diyAudio forums, Davey reported:

I see a few idiosyncrasies like [...] polarity reversals

@QuantAsylum indicated that this might indeed be an issue.

This might mean ASIO401 will need to flip the sign on some of the buffers, which makes me sad because so far I got away with avoiding any kind of alteration of the audio buffers themselves. It looks like that will have to change.

ASIO401 doesn't work in 64-bit apps on Windows ARM

This isssue mirrors dechamps/FlexASIO#206 which would affect ASIO401 as well.

The basic problem is the ASIO401 installer is confused about Windows ARM, and will only install the 32-bit x86 version of the driver. This will prevent ASIO401 from working in 64-bit x86 apps on Windows ARM. (ARM64 native apps are also unsupported, but that shouldn't surprise anyone.)

ASIO401 doesn't read toml file or enter any data in log file

I have created both in my user directory. Verified the toml file is readable with the 'type' command. I launch the QA401 app first, then quit. Then launch another ASIO app, the hardware works but settings in the toml file are ignored. Trying to reset the attenuator, it's always on.

I haven't seen anything show up in the log file.

Noise is output when using REW but not playing a signal

Steps to reproduce:

  • Open REW.
  • Start playing a test signal using ASIO401.
  • Stop playing the test signal.

Expected result:

Silence.

Actual result:

Spurious noise.

Weirdly, this only occurs when a test signal is not playing. The test signals themselves work fine.

I could reproduce this with ASIO401 1.1, but not with ASIO401 1.0.

REW version: V5.20 Beta 6.

Config used:

attenuator = false
bufferSizeSamples = 8192

Sample rate: 48 kHz.

ASIO401 sees an empty configuration file

Hello Etienne,
I’m trying 2nd party SW with QA401, e.g. Arta, Virtins SW, etc. According to ASIO401 I run QAAnalyzer and exit it. But once I exit relay returns back to -20dB. I made ASIO401.toml file:
#ASIO401 configuration file
attenuator = false
bufferSizeSamples = 1024
forceRead=false
and then I enable ASIO401.log file:
2020-06-18T10:59:45.7367505-04:00 3728 10596 Logfile opened: “C:\Users\galin\ASIO401.log”
2020-06-18T10:59:45.7369417-04:00 3728 10596 Log time source: GetSystemTimePreciseAsFileTime
2020-06-18T10:59:45.7369782-04:00 3728 10596 Host process: C:\VIRTINS Multi-Instrument 3.9\MIs.exe
2020-06-18T10:59:45.7370100-04:00 3728 10596 ASIO401 RelWithDebInfo x86 asio401-1.1 built on 2019-02-03T14:45:38Z
2020-06-18T10:59:45.7370360-04:00 3728 10596 — ENTERING CONTEXT: CASIO401()
2020-06-18T10:59:45.7370606-04:00 3728 10596 — EXITING CONTEXT: CASIO401() [OK]
2020-06-18T10:59:45.7370962-04:00 3728 10596 — ENTERING CONTEXT: init()
2020-06-18T10:59:45.7371313-04:00 3728 10596 Attempting to load configuration file: “C:\Users\galin\ASIO401.toml”
2020-06-18T10:59:45.7372475-04:00 3728 10596 Configuration file successfully parsed as valid TOML:
2020-06-18T10:59:45.7372927-04:00 3728 10596 Getting device info set for {FDA49C5C-7006-4EE9-88B2-A0F806508150}
2020-06-18T10:59:45.7378992-04:00 3728 10596 Enumerating device interfaces
2020-06-18T10:59:45.7379390-04:00 3728 10596 Getting device interface detail buffer size
2020-06-18T10:59:45.7379740-04:00 3728 10596 Getting device interface detail with buffer size 83
2020-06-18T10:59:45.7380044-04:00 3728 10596 Device path: ?\usb#vid_16c0&pid_4e27#5&a4e3133&0&2#{fda49c5c-7006-4ee9-88b2-a0f806508150}
2020-06-18T10:59:45.7386355-04:00 3728 10596 Opening file handle for USB device at path: ?\usb#vid_16c0&pid_4e27#5&a4e3133&0&2#{fda49c5c-7006-4ee9-88b2-a0f806508150}
2020-06-18T10:59:45.7386951-04:00 3728 10596 Initializing WinUSB

But -20dB is still there… No matter what I put in the configuration file, “Atten” LED is on and no clicks. It can be switched on/off only from Matt's app.

Interestingly enough, if I deliberately put a wrong value in TOML file, e.g. attenuator = fal, I still got: Configuration file successfully parsed as valid TOML:. I expect something like: fail to initialize in the log file..

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.