C/C++ にて　オーディオファイルを再生する

### 概要
C/C++ にて　オーディオファイルを再生する方法をまとめた。

オーディオファイルを再生するためには、
大きく２つの機能が必要です。

- １つ目の機能
サウンドデバイスを使って、音を鳴らす機能。
- ２つ目の機能
オーディオファイルを解析して、音の波形データを取り出す機能。

１つ目の機能は、サウンドデバイスを管理するOSに依存している。
OSごとに固有の方法があるが、OS依存度の小さいクロスプラットフォームのミドルウェアを使う方法を紹介する。
具体的には、 OpenAL, PulseAudio, SDL、irrKlang など。

２つ目の機能は、オーディオファイルの種類ごとに、専用のオーディオコーデックがある。
具体的には、 libmod,  libvorbis, libflac など。

MAC にて動作確認したコードを Github に公開した。
https://github.com/ohwada/MAC_cpp_Samples/blob/master/AudioPlayer.md

### OpenAL

OpenAL (Open Audio Library)
クロスプラットフォームのオーディオAPIである。
APIのスタイルと慣習は意図的にOpenGLと似せてある。

利用可能なプラットフォームOS
https://www.openal.org/platforms/

macOS では、プリインストールされている。
下記のように、g++ のコマンドオプションにOpenAL を指定する。
> g++ sample.cpp -framework OpenAL

まずは、簡易的に音を鳴らす。

(1) 音の波形データを作成する。

```
// 16ビット モノラル
#include <math.h>
#include<limits.h>

const int SAMPLINGRATE = 44100; // CD規格
int freq = 440; // 楽器の基準周波数 (Hz) 
int duration = 1; // 音の長さ (秒)
int data_size = SAMPLINGRATE  * duration;
int16_t* data = new int16_t[data_size];

// radian per sample rate
double delta = (2 * M_PI * freq ) / SAMPLINGRATE;

// Generate Sin wave 
for (int i = 0; i < data_size; i++) {
    data[i] = SHRT_MAX * sin(delta * i);
}
```

(2) OpenAL を初期化する

```
ALCdevice *device = alcOpenDevice(NULL);
ALCcontext *context = alcCreateContext(device, NULL);
alcMakeContextCurrent(context);
ALuint buffer;
ALuint source;
alGenBuffers(1, &buffer);
alGenSources(1, &source);
```

(3) 波形データを関連づけて、音を鳴らす

```
alBufferData(buffer, AL_FORMAT_MONO16, &data[0], data_size, SAMPLINGRATE);
alSourcei(source, AL_BUFFER, buffer);
alSourcePlay(source);
```

サンプルコードはこちらに。
https://github.com/ohwada/MAC_cpp_Samples/blob/master/OpenAL/play_tone.cpp


### wav ファイルを再生する

OpenALの拡張ライブラリである alure を使用する
https://kcat.strangesoft.net/alure.html

パッケージ管理ツールでインストールできる。
macOS の例：
brew install alure

alure の使い方の例

```
char *filename = "sample.wav"; // ファイル名
alureInitDevice(NULL, NULL);
ALuint source;
alGenSources(1, &source); 
ALuint buffer = alureCreateBufferFromFile(filename);
alSourcei(source, AL_BUFFER, buffer);
alSourcePlay(source);
```

サンプルコードはこちらに。
https://github.com/ohwada/MAC_cpp_Samples/blob/master/OpenAL/play_wav.cpp

wav はファイル構造が簡単で非圧縮なので、
alure を使用せずに、
C++ の標準関数で作成することもできる。

サンプルコードはこちらに。
https://github.com/ohwada/MAC_cpp_Samples/blob/master/wav/play_wav_with_openal.cpp


### mp3 ファイルを再生する

mp3 のオーディオコーデッックである libmad を使う
https://www.underbit.com/products/mad/

パッケージ管理ツールでインストールできる。
macOS の例：
brew install  libmad

libmad の使い方　

サンプルコード minimad.c が公開されている。
http://m.baert.free.fr/contrib/docs/libmad/doxy/html/minimad_8c-source.html

minimad.c は、
標準入力から mp3 を読み込んで、標準出力に raw pcm を出力する。

ビルドしたあと、下記のように使用する。
> ./a.out < sample.mp3 > out.raw

raw ファイルを再生するには、sox コマンドを使用する。
http://sox.sourceforge.net/

パッケージ管理ツールでインストールできる。
macOS の例：
brew install sox

sox コマンドで raw 形式を wav 形式に変換する。
> sox -r 44100 -e signed -b 16 -c 2 out.raw output.wav


C++ と libmad を使って、
mp3 ファイル を wav ファイルに変換するコードはこちら。
https://github.com/ohwada/MAC_cpp_Samples/blob/master/libmad/conv_wav.cpp


C++ と libmad を使って、
mp3 ファイルを再生するには、
raw pcm を OpenAL に関連づける。
切れ目なく再生するように、raw pcm をキューに積む。

```
alBufferData(buffer,  AL_FORMAT_STEREO16,  pcm_data, pcm_data_size,  44100);
alSourceQueueBuffers(source, 1, &buffer);
```

サンプルコードはこちらに。
https://github.com/ohwada/MAC_cpp_Samples/blob/master/libmad/play_mp3_with_openal.cpp