9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ASIO SDKで音を出す

Last updated at Posted at 2020-04-12

概要

ASIO規格に対応しているサウンドカードを使うために、SteinbergからASIO SDKが配布されています。
Windows上でこのSDKを使って、sin波を出力します。

環境構築

Visual Studio

  1. Visual Studio 2019をインストールしておいてください
  2. 公式チュートリアルを参考にしてC++でWindowsデスクトップアプリケーションを開発するための設定をしておいてください

SDKのダウンロード

配布ページからASIO SDKをダウンロードします。

サンプルソースコードのビルド

  1. sdkのフォルダを開いて、
    host->sampleの中にあるhostsample.dspをVisualStudioで開きます。プロジェクトのアップデートを促されるのでOKを押してアップデートします。
  2. VisualStudioの上にある「ローカルWindowsデバッガ-」ボタンを押して実行します。

ドライバのインストール

今の時点では、実行しても何も表示されず処理が終了します。これは、正しいASIOドライバが選択されていないからです。テスト用にASIO4ALLというドライバをインストールします。
ダウンロードしてインストールしてください。

サンプルプログラムの改造

ASIOドライバの列挙

hostsample.cppを以下のように編集します。

hostsample.cpp-10行目付近
     #include <string.h>
+    #include <iostream>
     #include "asiosys.h"
hostsample.cpp-450行目付近
 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を以下のように編集します。

hostsample.cpp-15行目付近
 // 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波の音声データを渡す処理を書こうと思います。しかし、サンプリングビットによって音声データの渡し方が少し変わるので、今のドライバが利用しているサンプリングビットを調べます。

hostsample.cpp-220行目付近
 // 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ビットのサンプリングビット数であることが分かりました。

次の作業に移る前に、数値の出力の処理はもう使わないのでコメントアウトしておきます。

hostsample.cpp-218行目
 // 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波を出力

以下のように編集します。

hostsample.cpp-10行目付近
 #include <string.h>
 #include <iostream>
+#include <cmath>
+#include <limits>
 #include "asiosys.h"
hostsample.cpp-170行目付近
 #endif
+
+ int t = 0;

 ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
hostsample.cpp-220行目付近
 // 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ファイルの出力もやってみたいです。

参照

金澤ソフト設計 : ASIOを利用してWAVファイルを再生する

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?