概要
ASIO規格に対応しているサウンドカードを使うために、SteinbergからASIO SDKが配布されています。
Windows上でこのSDKを使って、sin波を出力します。
環境構築
Visual Studio
- Visual Studio 2019をインストールしておいてください
- 公式チュートリアルを参考にしてC++でWindowsデスクトップアプリケーションを開発するための設定をしておいてください
SDKのダウンロード
配布ページからASIO SDKをダウンロードします。
サンプルソースコードのビルド
- sdkのフォルダを開いて、
host->sampleの中にあるhostsample.dspをVisualStudioで開きます。プロジェクトのアップデートを促されるのでOKを押してアップデートします。 - VisualStudioの上にある「ローカルWindowsデバッガ-」ボタンを押して実行します。
ドライバのインストール
今の時点では、実行しても何も表示されず処理が終了します。これは、正しいASIOドライバが選択されていないからです。テスト用にASIO4ALLというドライバをインストールします。
ダウンロードしてインストールしてください。
サンプルプログラムの改造
ASIOドライバの列挙
hostsample.cppを以下のように編集します。
#include <string.h>
+ #include <iostream>
#include "asiosys.h"
int main(int argc, char* argv[])
{
+ AsioDrivers ads;
+ char buffer[10][32] = {};
+ char* buf[10];
+ for (int i = 0; i < 10; ++i) {
+ buf[i] = buffer[i];
+ }
+ ads.getDriverNames(buf, 10);
+ for (int i = 0; i < 10; ++i) {
+ std::cout << buf[i] << std::endl;
+ }
// load the driver, this will setup all the necessary internal data structures
if (loadAsioDriver (ASIO_DRIVER_NAME))
この状態でプログラムを実行すると、PCにインストールされているASIOドライバの一覧が表示されます。
例えば、以下のように表示されます。
ASIO4ALL v2
Realtek ASIO
Yamaha Steinberg USB ASIO
「ASIO4ALL v2」ドライバが正しくインストールされていることが確認できます。
ASIOドライバの選択
hostsample.cppを以下のように編集します。
// name of the ASIO device to be used
#if WINDOWS
// #define ASIO_DRIVER_NAME "ASIO Multimedia Driver"
- #define ASIO_DRIVER_NAME "ASIO Sample"
+ #define ASIO_DRIVER_NAME "ASIO4ALL v2"
#elif MAC
プログラムを実行すると、選択されたASIOドライバが起動します、同時に、対応するASIOデバイスの詳細が取得され、表示されます。例えば以下のように表示されます。
asioVersion: 0
driverVersion: 2
Name: ASIO4ALL v2
ErrorMessage: No ASIO Driver Error
ASIOGetChannels (inputs: 2, outputs: 2);
ASIOGetBufferSize (min: 64, max: 2048, preferred: 512, granularity: 8);
ASIOGetSampleRate (sampleRate: 44100.000000);
ASIOOutputReady(); - Not supported
ASIOGetLatencies (input: 0, output: 997);
ASIO Driver started succefully.
23600645 ms / 223600645 ms / 883200 samples / TC: 00:00:00:00000
サンプリングビットの確認
今の段階では、ASIOドライバは起動したものの、音声データがドライバに渡されていないので、音が鳴りません。そこで、sin波の音声データを渡す処理を書こうと思います。しかし、サンプリングビットによって音声データの渡し方が少し変わるので、今のドライバが利用しているサンプリングビットを調べます。
// perform the processing
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
if (asioDriverInfo.bufferInfos[i].isInput == false)
{
+ std::cout << asioDriverInfo.channelInfos[i].type << std::endl;
// OK do processing for the outputs only
switch (asioDriverInfo.channelInfos[i].type)
asioDriverInfo.channelInfos[i].type
の中の値がサンプリングビット数に対応しています。
その数値と、サンプリングビットやサンプリングビットのデータ型の対応は以下のようになります。
数値 | サンプリングビット | サンプリングビットのデータ型 |
---|---|---|
16 | 16ビット | ASIOSTInt16LSB |
17 | 24ビット | ASIOSTInt24LSB |
18 | 32ビット | ASIOSTInt32LSB |
この状態で実装すると、手元の環境では以下のようになりました。
...
ASIO Driver started succefully.
18ms / 0 ms / 0 samples / TC: 00:00:00:00000
18
18
18
18
...
...
18という数値が出力されたことから、僕の環境では32ビットのサンプリングビット数であることが分かりました。
次の作業に移る前に、数値の出力の処理はもう使わないのでコメントアウトしておきます。
// perform the processing
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
if (asioDriverInfo.bufferInfos[i].isInput == false)
{
- std::cout << asioDriverInfo.channelInfos[i].type << std::endl;
+ //std::cout << asioDriverInfo.channelInfos[i].type << std::endl;
// OK do processing for the outputs only
switch (asioDriverInfo.channelInfos[i].type)
sin波を出力
以下のように編集します。
#include <string.h>
#include <iostream>
+#include <cmath>
+#include <limits>
#include "asiosys.h"
#endif
+
+ int t = 0;
ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
// buffer size in samples
long buffSize = asioDriverInfo.preferredSize;
+ t += buffSize;
+ int tempT = t;
// perform the processing
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
if (asioDriverInfo.bufferInfos[i].isInput == false)
{
//std::cout << asioDriverInfo.channelInfos[i].type << std::endl;
+ int32_t* dist = static_cast<int32_t*>(asioDriverInfo.bufferInfos[i].buffers[index]);
// OK do processing for the outputs only
switch (asioDriverInfo.channelInfos[i].type)
{
case ASIOSTInt16LSB:
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
break;
case ASIOSTInt24LSB: // used for 20 bits as well
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
break;
case ASIOSTInt32LSB:
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
+ for (int i = 0; i < buffSize; ++i) {
+ *(dist++) = (INT32_MAX/2) * std::sin((float)tempT++ / 10.0f);
+ }
break;
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
asioDriverInfo.bufferInfos[i].buffers[index]
にはi番目の出力チャンネルに渡す音声データへのポインタが入っています。buffSize
は一度に書き込むデータの個数です。
結論
ASIO SDKを使ってsin波を出すことが出来ました。
気が向いたらWAVファイルの出力もやってみたいです。