音声信号処理、wavファイル波形表示
音声信号処理の勉強の為、書籍等を参考にして、実際にソフトウエア等を作成し実験してみた。今回は、wavファイルを読み込んで音声信号波形データを表示させる。
参考にさせていただいた書籍は、
・サウンドエフェクトのプログラミング Cによる音の加工と音源合成
以前Free C++ Compiler (BCC102)をインストールする為、以下のWEBページ
・実践編・Free C++ Compiler 開発環境ポータブル化
を参考にさせていただいていたが、この中でGLUTを使う為セットアップ方法も書かれていて自分も参考にしてFree C++ Compiler (BCC102)でGLUTが使用出来る様にセットアップしていた。
OpenCV等の他のライブラリーを使用する方が準備に手間が掛かる為、今回はwavファイルの波形をGLUTでグラフィック表示させる事にした。
GLUTの使い方は以下のWEBページを参考にさせていただいた。
・グラフィックスの基礎
書籍「サウンドエフェクトのプログラミング Cによる音の加工と音源合成」のP53~P55の「3.7 正弦波音ファイルの作成」のサンプルプログラムを試していた。
念の為、「3.7 正弦波音ファイルの作成」のサンプルプログラムは以下の様にしてコンパイルした。
bcc32c -c wavwrite.c
bcc32c sine.c wavwrite.obj
実行例として、
・例1 44,100サンプル(1秒間), 最大値16,383(0x3FFF半分), 音声周波数1kHz, サンプリングレート44.1kHz, ファイル名test1000hz.wav
sine 44100 16383 1000 44100 test1000hz.wav
ファイル作成OK
・例2 念の為これは試さないで下さい。
44,100サンプル(1秒間), 最大値65,535(0xFFFF2倍), 音声周波数1kHz, サンプリングレート44.1kHz, ファイル名test1000hz_x2.wav
sine 44100 65535 1000 44100 test1000hz_x2.wav
ファイルが出来ないで終了した。ハングしたかも。(16bit符号付き整数の範囲を超えている為、再生してはいけない不定な数値のデータになるとは思ったが、、、)
・例3 44,100サンプル(1秒間), 最大値32,767(0x7FFFフル), 音声周波数1kHz, サンプリングレート44.1kHz, ファイル名test1000hz_full.wav
sine 44100 32767 1000 44100 test1000hz_full.wav
ファイル作成OK
当初、出来た波形の確認は、Sazanamiを使用させていただいていたが、勉強の為にも自分で表示プログラムを作ってみる事にした。
作成したプログラムは、wav_data_disp.c
今回も音声処理の為、書籍「サウンドエフェクトのプログラミング Cによる音の加工と音源合成」のwavlib.hとwavread.cを使用させていただいた。
コンパイル方法は、
bcc32c -c wavread.c
bcc32c wav_data_disp.c wavread.obj glut32.lib
実行方法は、
wav_data_disp
実行後、表示するwavファイル名を入力する。
test1000hz.wav等
以下の様に波形が表示される。
test1000hz_full.wavの波形も表示させた。
グラフィック表示の横の目盛りは、上から100%, 50%, 0%, -50%, -100%で
test1000hz.wavが半分程のふり幅である事と、
test1000hz_full.wavがふり幅が最大値から最小値まである事が確認出来た。
以下にプログラムwav_data_disp.cを載せる。
また、今回も書籍のwavlib.hとwavread.cをそのまま使わせていただいている為、こちらは載せるのを控えています。
16bitデータ、1chの表示に機能が絞られています。
// wavファイルのdataを波形表示させる
#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h> // GLUT
#include "wavlib.h" // wavライブラリー使用手続き
int WINDOW_WIDTH = 500; // ウィンドウの横幅
int WINDOW_HEIGHT = 500; // ウィンドウの高さ
wav_head bufhead; // wavファイルヘッダー部分格納
void init()
{
glClearColor(1.0, 1.0, 1.0, 1.0); // r, g, b, 不透明白
}
void display()
{
int i;
int x_step = 2;
//int x_max = 499 - 2;
int x_lim;
int wav_yd;
int wav_yd_ofset = 250;
int wav_yd_n1 = 0; // 前回のy座標
short *ibuf;
ibuf = bufhead.data;
// ウィンドウ表示内容のクリア
glClear(GL_COLOR_BUFFER_BIT);
// 目盛り線+100%
glColor3d(0.5, 0.5, 0.5); // グレー
glBegin(GL_LINES);
glVertex2d(0, 450);
glVertex2d(WINDOW_WIDTH - 1, 450);
glEnd();
// 目盛り線+50%
glColor3d(0.5, 0.5, 0.5); // グレー
glBegin(GL_LINES);
glVertex2d(0, 350);
glVertex2d(WINDOW_WIDTH - 1, 350);
glEnd();
// 目盛り線0%
glColor3d(0.5, 0.5, 0.5); // グレー
glBegin(GL_LINES);
glVertex2d(0, 250);
glVertex2d(WINDOW_WIDTH - 1, 250);
glEnd();
// 目盛り線-50%
glColor3d(0.5, 0.5, 0.5); // グレー
glBegin(GL_LINES);
glVertex2d(0, 150);
glVertex2d(WINDOW_WIDTH - 1, 150);
glEnd();
// 目盛り線-100%
glColor3d(0.5, 0.5, 0.5); // グレー
glBegin(GL_LINES);
glVertex2d(0, 50);
glVertex2d(WINDOW_WIDTH - 1, 50);
glEnd();
// 波形描画
x_lim = (WINDOW_WIDTH - 3) / x_step;
if (x_lim > (bufhead.Nbyte / bufhead.bl_size)) x_lim = bufhead.Nbyte / bufhead.bl_size;
for (i = 0; i < x_lim; i++) {
// 今回のy座標計算
wav_yd = (int)((double)ibuf[i] * (400.0 / 65535.0));
if (wav_yd < -200) wav_yd = -200;
else if (wav_yd > 200) wav_yd = 200;
// 前回のデータからの縦ライン描画
glColor3d(0.0, 0.0, 0.0); // 黒
glBegin(GL_LINES);
glVertex2d(i * x_step, wav_yd_n1 + wav_yd_ofset);
glVertex2d(i * x_step, wav_yd + wav_yd_ofset);
glEnd();
// 今回のデータからの横ライン描画
glColor3d(0.0, 0.0, 0.0); // 黒
glBegin(GL_LINES);
glVertex2d(i * x_step, wav_yd + wav_yd_ofset);
glVertex2d((i + 1) * x_step, wav_yd + wav_yd_ofset);
glEnd();
// 今回のデータ保存
wav_yd_n1 = wav_yd;
}
glFlush();
}
void reshape(int width, int height)
{
// OpenGLウィンドウの描画範囲を設定
// 下記は描画範囲が[0, width] x [0, height]となるように設定している
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, (double)width, 0.0, (double)height);
WINDOW_WIDTH = width;
WINDOW_HEIGHT = height;
}
// 実行方法: wav_data_disp
// wavファイル名は後から指定
int main(int argc, char** argv)
{
char *fnI; // ファイル名格納
int i;
// ファイル名関係
fnI = calloc(100,sizeof(char)); // メンバー数, 1個のサイズ
printf("wav file name = ");
scanf("%s", fnI); // キーボード入力 文字列フォーマット, 出力する変数
// wavファイル読み込み
wavread(&bufhead, fnI);
// GLUT
glutInit(&argc, argv); // GLUT 初期化
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); // ウィンドウのサイズを設定
glutCreateWindow(fnI); // ウィンドウの作成 (引数はウィンドウのタイトル)
glutDisplayFunc(display); // 描画に使う関数の登録
glutReshapeFunc(reshape); // ウィンドウのサイズ変更時に呼ばれる関数の登録
//glutMouseFunc(mouse); // マウス操作時に呼ばれる関数の登録
init(); // OpenGLの初期化処理 (これはコールバック関数ではないので直接呼び出す)
glutMainLoop(); // 描画ループの開始
}
今回は以上です。