LoginSignup
23
21

More than 5 years have passed since last update.

[vDSP][信号処理]オーディオ・音声分析への道3 Libsndfile

Last updated at Posted at 2014-06-13

オーディオ・音声分析への道 その3 Libsndfile

今回は演算結果をオーディオデータとして出力したいと思います。
オーディオデータをC言語で扱う為のライブラリはいくつかあると思いますが、ここではLibsndfileを使いたいと思います。

Libsndfile はオーディオデータを扱う為のCライブラリです。データを読み込んだり、ファイルに書き出す事ができます。
対応しているオーディオフォーマットは沢山ありますが、中でもWAVやAIFF、RAW、OGGに対応しています。

ではLibsndfileのダウンロード、Xcodeへの追加設定を説明します。

Macportのインストール

LibsndfileのMacへのインストールはMacportを使うと便利です。
Macportは、Macへのソフトウェア導入を簡略化してくれるパッケージ管理システムです。
ここからファイルをダウンロードします。(英語サイト)

2.2.1. Mac OS X Package Installから、自分のOSにあうパッケージをダウンロードします。
筆者はMavericksなので、MacPorts-2.3.0-10.9-Mavericks.pkgをダウンロードします。

Libsndfile01.jpg

インストールが完了したら、ターミナルを起動して確認をします。

libsndfile02.png

ターミナルに

$ port version

と打ち、returnターン!!
ちなみにportとはMacPortのPortですね。

Version: 2.3.0

上のようにVersionが表示されればOKです。

ここで、念のためMacportを最新バージョンにアップデートしておきます。
この為のコマンドは、

$ sudo port -d self update

とします。すると、パスワードを尋ねられるので、パスワードを入力してreturn!
するとターミナルにログが表示されアップデートが始まります。最後に、

The ports tree has been updated. To upgrade your installed ports, you should run port upgrade outdated

と表示されればOKです。

Libsndfileのインストール

さぁ、ここからlibsndfileのインストールです。
ターミナルに、

$ sudo port install libsndfile

とします。もしパスワードを尋ねられれば、また入力します。
universalモード(intel MacとG5, G4Mac両用)でインストールする場合は、

$ sudo port install libsndfile +universal

とします。

Xcodeの設定

Xcodeに必要なインストールされたLibsndfileのファイルは三つあり、

  • sndfile.h (C言語のヘッダ) : 場所 Macintosh HD/opt/local/include/sndfile.h
  • sndfile.hh(C++のヘッダ) : 場所 Macintosh HD/opt/local/include/sndfile.hh
  • libsndfile.a(ライブラリ) : 場所 Macintosh HD/opt/local/include/libsndfile.a

となります。
上記三つのファイルをXcodeのプロジェクトに追加します。
(インストールされたファイルを移動せず、そのままリンクします。)

Libsndfile03.png

これで準備完了です。

sin波を生成してWAVファイルに書き出す

さて、いよいよプログラミングをしましょう。
まずは、sin波を生成して、それをWAVファイル(ステレオ, 16bit, 44100Hz)に書き出してみたいと思います。

では必要なヘッダをインクルードします。

main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

ここで、Libsndfileのインクルードは以下の様にします。

main.c
#import"sndfile.h"

次に、sin波を生成する為に必要な情報を定義しておきます。

main.c
#define PAI 3.14159265358979323846264338 // PAI
#define SAMPLE_RATE 44100 //sampling rate
#define LENGTH 4 // 4 seconds
#define AMPLITUDE 1.0
#define FREQUENCY 440 // frequency Hz

PAIはsin波生成で使用する円周率、サンプリングレートは44.1kHz, オーディオデータの長さは4秒, 音の大きさAMPLITUDEレンジはデータタイプがfloat型の場合は1.0です。FREQUENCYは生成するsin波の周波数を指定します。

Libsndfileでオーディオデータを使用する際には、C言語のFILE型の構造体を使うのではなく、Libsndfile準拠のSNDFILE型構造体を使用します。
これは以下の様に宣言します。

main.c
SNDFILE *fp;

また、オーディオデータの各種設定はSF_INFO型の構造体に格納します。今回とは逆に、オーディオデータを読み込む場合は、SF_INFO型構造体に読み込んだオーディオデータの情報が格納される事になります。

main.c
SF_INFO sfinfo;

念のため、sfinfoの中身を初期化します。

main.c
memset(&sfinfo,0,sizeof(sfinfo));

sfinfoに必要なデータを格納します。

main.c
sfinfo.samplerate = SAMPLE_RATE;
sfinfo.frames = SAMPLE_RATE*LENGTH;
sfinfo.channels = 2;
sfinfo.format = (SF_FORMAT_WAV | SF_FORMAT_PCM_16);

ここれ、sfinfo.formatにはオーディオデータの種類と、bit数を設定します。
WAVデータの場合は SF_FORMAT_WAV とし、AIFFデータの場合は SF_FORMAT_AIFF 等とします。
bit数はとりあえず以下の四種類を知っておけば良いです。

main.c
SF_FORMAT_PCM_S8= 0x0001,       /* Signed 8 bit data */
SF_FORMAT_PCM_16= 0x0002,       /* Signed 16 bit data */
SF_FORMAT_PCM_24= 0x0003,       /* Signed 24 bit data */
SF_FORMAT_PCM_32= 0x0004,       /* Signed 32 bit data */

次にsin波生成用のメモリ領域を確保します。

main.c
float *buffer;
buffer = malloc(2*SAMPLE_RATE*LENGTH*sizeof(float));

データ型はfloatです。
ここで、bufferのサイズは、
2(チャンネル数) x (サンプリングレート) x オーディオデータの長さ x float型データサイズ
となります。一秒間に44100の解像度で標本化されるので、44100個のデータがチャンネル毎に格納されます。

C言語でファイルを生成する場合は **fopen()** を使用しますが、Libsndfileの場合は **sf_open()** を使用します。
main.c
if(!(fp = sf_open("SinWave.wav", SFM_WRITE, &sfinfo))){
        printf("Error : Could not open output file .\n");

        return 1;
    }

第一引数にファイルのアドレス、
第二引数にオープンのタイプ
+ SFM_READ // 読み込み
+ SFM_WRITE // 書き込み
+ SFM_RDWR // 追加

第三匹数にsfinfoを入れます。
ファイルの生成に失敗するとNULLを返します。

次にsin波を計算してbufferに格納します。

main.c
for(i=0;i<SAMPLE_RATE*LENGTH;i++){ // STEREO
        //440hz
    buffer[2*i] = AMPLITUDE * sin((float)FREQUENCY / SAMPLE_RATE * 2 * PAI * i);
        //880hz
    buffer[2*i+1] = AMPLITUDE * sin((float)FREQUENCY*2 / SAMPLE_RATE * 2 * PAI * i);    
    }

今回は、1チャンネルに440hzのsin波を、2チャンネルに二倍の880hzのsin波を入れました。左右で音高が変わります。

最後に、wavデータファイルとして書き出します。

main.c
if(sf_write_float(fp, buffer,sfinfo.channels * SAMPLE_RATE*LENGTH)!= sfinfo.channels * SAMPLE_RATE*LENGTH)
    puts(sf_strerror (fp));

sf_write_float()を使用します。
これは用途によって、以下の種類が用意されています。

main.c
sf_count_t sf_read_short    (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
sf_count_t sf_write_short   (SNDFILE *sndfile, const short *ptr, sf_count_t items) ;
sf_count_t sf_read_int      (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
sf_count_t sf_write_int     (SNDFILE *sndfile, const int *ptr, sf_count_t items) ;
sf_count_t sf_read_float    (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
sf_count_t sf_write_float   (SNDFILE *sndfile, const float *ptr, sf_count_t items) ;
sf_count_t sf_read_double   (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
sf_count_t sf_write_double  (SNDFILE *sndfile, const double *ptr, sf_count_t items) ;

sf_strerror にはエラーメッセージが格納されます。必要に応じてコンソールに出力します。

最後に fp をクローズして終わりです。

main.c
sf_close(fp);

全体のコードです。

main.c
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#import"sndfile.h"
#define PAI 3.14159265358979323846264338 // PAI
#define SAMPLE_RATE 44100 //sampling rate
#define LENGTH 4 // 4 seconds
#define AMPLITUDE 1.0// 16bit
#define FREQUENCY 440 // frequency Hz

int main(void)

{
    SNDFILE *fp;
    SF_INFO sfinfo;
    int i;

    float *buffer;
    buffer = malloc(2*SAMPLE_RATE*LENGTH*sizeof(float));

    //initialization
    memset(&sfinfo,0,sizeof(sfinfo));

    sfinfo.samplerate = SAMPLE_RATE;
    sfinfo.frames = SAMPLE_RATE*LENGTH;
    sfinfo.channels = 2;
    sfinfo.format = (SF_FORMAT_WAV | SF_FORMAT_PCM_16);

    if(!(fp = sf_open("SinWave.wav", SFM_WRITE, &sfinfo))){
        printf("Error : Could not open output file .\n");
        return 1;
    }

    for(i=0;i<SAMPLE_RATE*LENGTH;i++){ // STEREO    
        //440hz
    buffer[2*i] = AMPLITUDE * sin((float)FREQUENCY / SAMPLE_RATE * 2 * PAI * i);
        //880hz
    buffer[2*i+1] = AMPLITUDE * sin((float)FREQUENCY*2 / SAMPLE_RATE * 2 * PAI * i);    
    }

    if(sf_write_float(fp, buffer,sfinfo.channels * SAMPLE_RATE*LENGTH)!= sfinfo.channels * SAMPLE_RATE*LENGTH)
        puts(sf_strerror (fp));

    sf_close(fp);

    return 0;
}

ビルド・実行すると、SinWave.wavというファイルが出力されます。
Audacity等のフリーソフトでオーディオデータを開いてみると、波形が確認できます。

波形を拡大すると、このように見えます。

libsndfile04.png

Libsndfileの使い方のみになりましたが、次回はvDSPと絡めていきます...

23
21
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
23
21