audio_asio.h
ASIO output, without Steinberg's SDK.
#include <sonore/audio_asio.h>- 9types
- 4other declarations
- Guides: Platforms and formats
On this page
Design notes
ASIO is the reason a Windows musician can run at 64 samples instead of 512. WASAPI in shared mode adds a buffer nobody asked for; in exclusive mode it is better and still not an interface driver talking to its own hardware. Every serious Windows DAW offers ASIO first, and a standalone that cannot is a standalone people use once.
Why there is no asio.h here
Steinberg's ASIO SDK may not be redistributed. That is exactly why every framework makes you fetch it yourself, and why this SDK listed ASIO as absent for most of its life.
It is not needed. IASIO is a COM vtable, and an interface declared in order to INTEROPERATE is not the other party's source. This file declares that vtable itself, the same thing it already does for LV2's UI descriptor and LV2's worker interface, neither of which is vendored either. No Steinberg code is compiled, linked, or shipped.
I am not a lawyer and this is worth checking before a commercial release. What I can say precisely is what this file contains: a vtable layout, a registry key name, and our own code.
What ASIO does differently from every other audio API
- A driver is instantiated with CoCreateInstance where the IID EQUALS the CLSID. It is not a real COM interface and does not answer QueryInterface for anything else.
- Buffers are PER CHANNEL and in the driver's own sample format, which is usually 32-bit integer and is whatever the hardware actually wants.
- There is one driver at a time, machine-wide. Opening a second while the first is running fails, and that is the hardware's rule rather than ours.
Types 9
One clock a driver can sync to, as getClockSources fills it in. The ASIO SDK's clock-source structure, layout unchanged (see above); nothing in this SDK selects a clock -- that is the driver's own control panel's job.
What a driver says about one channel: the caller sets channel and isInput, getChannelInfo fills in the rest. type is the sample format, one of the kAsio codes in asio_format.h, and is asked for separately for input and output because the two need not agree. The ASIO SDK's channel-info structure, layout unchanged (see above).
One channel handed to createBuffers: the caller sets isInput and channelNum, and the driver writes the two halves of its double buffer into buffers, which the buffer-switch callback then indexes by the half it is on. The array of these must stay alive until disposeBuffers. The ASIO SDK's buffer-info structure, layout unchanged (see above).
A 64-bit system time in nanoseconds, split into two 32-bit halves the way the ASIO SDK's time-stamp structure is (layout unchanged, see above).
A 64-bit sample position, split into two 32-bit halves the way the ASIO SDK's samples structure is (layout unchanged, see above).
The four functions a driver calls back, in the ASIO SDK's order (layout unchanged, see above).
The driver KEEPS the pointer createBuffers is given rather than copying the table, so the table must outlive the buffers: AsioOutput holds it as a member for exactly that reason. There is no user-data field, which is why only one driver can be open at a time. bufferSwitch runs on the driver's thread -- the audio thread. AsioOutput leaves bufferSwitchTimeInfo null and its asioMessage answers no when a driver asks whether time info is supported (hostMessageReply in asio_format.h), so drivers call bufferSwitch.
class IAsio : public IUnknown
The driver interface, declared rather than included.
The ORDER of these is the ABI: a vtable is positional, so a method inserted or omitted shifts every one below it and the first call lands somewhere else entirely. It is transcribed from the published interface and its shape is checked at run time before anything is called -- see the sanity check in open().
One installed driver, as the registry describes it.
One ASIO driver, opened and streaming.
ONE AT A TIME, machine-wide, and that is ASIO's rule rather than ours: the callbacks are bare C function pointers with no user-data cookie, so a host has nowhere to put a this. Every ASIO host on Windows keeps a single static instance for exactly this reason, and a second driver opened while the first is running fails at the hardware anyway. So open() refuses while another AsioOutput has a driver open: stop that one first.
Functions 1
- fn
inline std::vector<DriverInfo> listDrivers()Every ASIO driver installed on this machine.asio::listDrivers · audio_asio.h:201