How to manage ASIO drivers
ASIO (Audio Stream Input/Output) is a sound card driver protocol for digital audio specified by Steinberg, providing a low-latency and high fidelity interface between a software application and a computer's sound card. ASIO bypasses the normal audio path from the user application through layers of intermediary Windows operating system software, so that the application connects directly to the hardware of the sound card. Each layer that is bypassed means a reduction in latency, the delay between an application sending sound to the sound being reproduced by the sound card.
By default Active DJ Studio enumerates output devices (sound cards) supporting the DirectSound protocol: in order to let Active DJ Studio enumerating devices supporting ASIO drivers, you need to make a call to the InitDriversType method and to specify which kind of drivers/protocols your application will support and, in case you should need supporting both ASIO and DirectSound at the same time, in which order; if a certain sound card should support both DirectSound and ASIO drivers, it would be enumerated as two different sound cards, one supporting DirectSound and one supporting ASIO (*).
The call to the InitDriversType method is mandatory before performing calls to the InitDJSystem, GetOutputDevicesCount and GetOutputDeviceDesc methods: if the InitDriversType method should be called at a later time, it would report back an error; if for any reason you should need calling it at a later time, you would need performing the following sequence of calls:
1. ResetEngine method
2. InitDriversType method
4. ResetControl method
After having initialized the type of driver(s) in use through the InitDriversType method, it will be possible enumerating available output devices through the GetOutputDevicesCount and GetOutputDeviceDesc methods: depending upon the drivers set, these methods will return the overall list of available output devices (DirectSound + ASIO) so it will be possible setting them inside the nOutputx parameters of the InitDJSystem method. At a later time you can obtain the driver in use by a specific output device through the GetOutputDeviceDriverType method.
If the InitDriversType method should be set to initialize the use of ASIO devices, you could access specific ASIO features through methods exposed by the ASIO property that implements the ASIO COM object:
|•||Enumerating available ASIO devices through the ASIO.DeviceGetCount and ASIO.DeviceGetDesc methods: it's important to note that this kind of enumeration will only report existing ASIO devices and not the overall list of available output devices as reported by the GetOutputDevicesCount and GetOutputDeviceDesc methods.|
|•||Obtaining the zero-based index of an ASIO device inside the overall list of available output devices through the ASIO.DeviceGetOutputIndex method.|
|•||Given the zero-based index of an ASIO device inside the overall list of available output devices, obtaining the zero-based index of the same ASIO device inside the list of available ASIO devices through the ASIO.DeviceGetIndexFromOutput method.|
|•||For each ASIO device, enumerating the list of available input and output channels through the ASIO.DeviceGetChannelsCount and ASIO.DeviceGetChannelDesc methods.|
|•||Displaying the control panel provided by the ASIO driver of a specific device through the ASIO.ControlPanelDisplay method.|
|•||Obtaining the absolute pathname of the file containing the ASIO driver of a specific ASIO device through the ASIO.DeviceGetDriverPathname method.|
|•||Starting and stopping the usage of a specific ASIO device through the ASIO.DeviceStart and ASIO.DeviceStop methods.|
The call to the ASIO.DeviceStart method is mandatory in order to perform playback of the loaded sound on a specific ASIO device. You can know if a specific ASIO device is already started through the ASIO.DeviceIsStarted method.
After starting an ASIO device, it will be possible performing the following tasks:
|•||Playing a sound on the device|
|•||Using input channels as playback channels through the ASIO.AttachInputChannelToPlayer method: this allows to get sound coming from an input channel of the ASIO device, for example the Line-in or the Microphone, and to send it in playback with very low latency.|
|•||Redirecting the output of a certain player to a specific output channel through the ASIO.PlayerOutputChannelSet and ASIO.PlayerOutputChannelGet methods: with multi-channels sound cards (5.1 and 7.1) this allows performing speakers management.|
|•||Getting and setting the volume for input and output channels through the ASIO.DeviceMasterVolumeGet and ASIO.DeviceMasterVolumeSet methods (applies the same volume level to all channels in one shot) and through the ASIO.DeviceChannelVolumeGet and ASIO.DeviceChannelVolumeSet methods (applies the volume level on a specific channel allowing separate volume level for each channel).|
|•||Obtaining the current latency, expressed in samples per second, for input and output channels as reported by the ASIO driver itself through the ASIO.DeviceLatencyGet method.|
An interesting feature of ASIO devices is the channel mirroring, a capability that allows replicating the same sound on more output channels of the same ASIO device; this can be obtained with a specific setting of the nChannelMode parameter of the ASIO.DeviceStart method:
|•||when the nChannelMode parameter is set to ASIO_CHANNEL_MODE_MIRROR_STEREO, the control will mirror the output of channel "0" to other pair channels (2, 4, etc.) and the output of channel "1" to other odd channels (3, 5, etc.). When playing a stereo sound on an ASIO device having 8 output channels, this will allow hearing the same stereo sound on the 4 available channel pairs.|
|•||when the nChannelMode parameter is set to ASIO_CHANNEL_MODE_MIRROR_MONO, the control will mirror the output of channel "0" to all of the other available channels (1, 2, 3, 4, etc.). When playing a mono sound on an ASIO device having 8 output channels, this will allow hearing the same mono sound on all of the 8 channels.|
With regards to playback of loaded sounds, it's important to note that the possibility to redirect the sound stream to output devices having different nature (ASIO or DirectSound) has been maintained. In order to achieve this feature we had the need to internally create an embedded "Stream Mixer" for each output device; this approach is quite similar to what has been described inside the How to use custom Stream Mixers tutorial but in this case you don't need to allocate a new custom Stream Mixer through your own code because the control will automatically allocate it for you. Below you can see the architecture applied:
In case the output of Player 0 and/or Player1 should be redirected to a different output device, the StreamOutputDeviceSet method would automatically disconnect the PCM stream from the internal Stream Mixer of the current output device and will reconnect it to the internal Stream Mixer of the new output device.
As for custom Stream Mixers described inside the How to use custom Stream Mixers tutorial, also in this case the Stream Mixer owns a unique identifier that can be obtained through the StreamMixerGetIdFromOutput method: through this unique identifier you can apply further effects to the mixed streams, for example you could apply a custom DSP or modify the Preamplifier volume: for this purpose the unique identifier can be used in place of the nPlayer parameter for all of the methods that will modify the output stream, like volume-related methods and all of the methods described inside the How to apply special effects to a playing sound tutorial. For obvious reasons, respect to custom Stream Mixers, you cannot redirect the mixed stream in output from the Stream Mixer to a different output device.
As seen on the graphic above, as for custom Stream Mixers, the Mixed stream being sent to the output device can be redirected to one of the following destinations:
|•||Through the use of an external encoder (Lame.exe for MP3 or OggEnc.exe for Ogg Vorbis), to a Shoutcast or Icecast server: in this case the control behaves as a Shoutcast/Icecast source.|
|•||In combination with our Active Sound Recorder control, directly to an output file whose format can be predisposed inside Active Sound Recorder itself.|
IMPORTANT NOTE ABOUT PERFORMANCES: When the output of the stream mixer is sent to the recorder control and/or to a streaming server, a too much low latency set into the ASIO driver could cause unwanted gargling on the audio stream: in this specific case it's recommended that the latency of the ASIO driver is set to 512 samples per second or higher.
In case you should simply need to render audio data incoming from one or more input channels to one or more output channels directly, with the advantage of a smaller CPU footprint, a possible alternative to the ASIO.DeviceStart method would to invoke the ASIO.DeviceListenInputStart method: the limitation of this approach would be the fact that you would loose the capability to record or cast incoming audio data. When the ASIO device is started in this way, you may pause direct playback through the ASIO.DeviceListenInputPause method and resume playback through the ASIO.DeviceListenInputResume method.
In this case direct playback is not performed through the stream mixer described above, as incoming audio data is rendered directly to the output channel(s), but you can still apply special effects to audio data being rendered by obtaining the index of the involved internal player through the ASIO.DeviceListenInputPlayerGet method and by using the returned index with any of the methods of the Effects COM object or with the StreamVolumeLevelSet method.
Also in this case, the ASIO device can be stopped through the ASIO.DeviceStop method.
Samples of usage of ASIO drivers in Visual C++ 6 and Visual Basic 6 can be found inside the following samples installed with the product's setup package:
If the Active Sound Suite package has been installed, a further sample demonstrating the possibility to record and casting the output of the stream mixer is available:
(*) The possibility for a certain output device to support both DirectSound and ASIO at the same time could be compromised if the specific driver in use shouldn't be able to manage the situation: usually in these cases, quite limited in our experience, it will be only possible playing back the loaded sound through the ASIO protocol.