WAVEファイルのノコギリ波を作って再生してみる
前回はWAVEファイルからデータを抽出し波形をプロットしてグラフ化した。
今回は逆にWAVEファイルを作成してちゃんと再生できるか試してみる。
目次
ノコギリ波の作成
下記条件でノコギリ波を作成する。
# | 構成要素 | 値 |
---|---|---|
1 | 振幅 | 15000(レンジは-15000~15000) |
2 | 振動数 | 50Hz |
3 | サンプリング周波数 | 44.1kHz |
4 | 再生時間 | 3秒 |
5 | チャンネル数 | 2(ステレオ) |
6 | 量子化精度 | 16bit |
上記ノコギリ波のサンプリング時刻 t における値 S(t) を式にすると次の通りになる。

(サンプリング周波数/振動数)はノコギリ波の傾きを表す。
ノコギリ波生成プログラム
前回のソースを流用して下記の通り作成した。
sawtooth_wav.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#define WAVE_FORMAT_PCM 0x0001 /* PCM */
#define CHANNEL_STEREO 0x0002 /* ステレオ */
#define SAMPLING_PER_SEC (0x0000AC44) /* 44.1kHz */
#define SOUND_LENGTH (SAMPLING_PER_SEC * 3) /* 3sec */
#define BLOCK_SIZE 0x0004 /* 4byte */
#define DATA_SIZE (SOUND_LENGTH * BLOCK_SIZE) /* DATAサイズ */
#define AMPLITUDE 0x3A98 /* 振幅は±15000 */
#define PERIOD 0x0032 /* 50Hz */
#define BIT_PER_SAMPLE 0x0010 /* 16bit */
#define SLOPE (SAMPLING_PER_SEC/PERIOD) /* 波の傾き */
/* RIFFチャンク */
typedef struct {
char chunk_id[4]; /* チャンク識別子('RIFF'固定) */
uint32_t chunk_size; /* チャンクサイズ */
char format_type[4]; /* フォーマットタイプ('WAVE'固定) */
} RIFF_chunk_t;
/* fmt チャンク */
typedef struct {
char chunk_id[4]; /* チャンク識別子('fmt '固定) */
uint32_t chunk_size; /* チャンクサイズ */
uint16_t format_type; /* フォーマットタイプ */
uint16_t channel; /* チャンネル数 */
uint32_t sample_per_sec; /* サンプリング周波数 */
uint32_t byte_per_sec; /* 1秒あたりバイト数 */
uint16_t block_size; /* ブロックサイズ */
uint16_t bit_per_sample; /* 量子化精度 */
} fmt_chunk_t;
/* dataチャンク */
typedef struct {
char chunk_id[4]; /* チャンク識別子('data')固定 */
uint32_t chunk_size; /* チャンクサイズ(データ長) */
uint8_t dat[0]; /* データ(可変長) */
} data_chunk_t;
typedef struct {
RIFF_chunk_t riff;
fmt_chunk_t fmt;
data_chunk_t data;
} wave_format_t;
typedef struct {
int16_t left;
int16_t right;
} wave_stereo_t;
int main(int argc, char*argv[])
{
if (argc != 2) {
fprintf(stderr, "usage:%s <output file>\n", argv[0]);
goto error_end;
}
FILE* fp = fopen(argv[1], "wb+");
if (NULL == fp) {
perror("fopen");
goto error_end;
}
wave_format_t* wave =
(wave_format_t* )malloc(sizeof(*wave) + DATA_SIZE);
if (NULL == wave) {
perror("malloc");
goto error_close_end;
}
/* RIFF */
memcpy(wave->riff.chunk_id, "RIFF", sizeof(wave->riff.chunk_id));
wave->riff.chunk_size = sizeof(*wave)+DATA_SIZE;
memcpy(wave->riff.format_type, "WAVE", sizeof(wave->riff.format_type));
/* fmt */
memcpy(wave->fmt.chunk_id, "fmt ", sizeof(wave->fmt.chunk_id));
wave->fmt.chunk_size = sizeof(fmt_chunk_t) -
(sizeof(wave->fmt.chunk_id)+sizeof(wave->fmt.chunk_size));
wave->fmt.format_type = WAVE_FORMAT_PCM;
wave->fmt.channel = CHANNEL_STEREO;
wave->fmt.sample_per_sec = SAMPLING_PER_SEC;
wave->fmt.byte_per_sec = SAMPLING_PER_SEC * BLOCK_SIZE;
wave->fmt.block_size = BLOCK_SIZE;
wave->fmt.bit_per_sample = BIT_PER_SAMPLE;
/* data */
memcpy(wave->data.chunk_id, "data", sizeof(wave->data.chunk_id));
wave->data.chunk_size = DATA_SIZE;
int t;
for (t = 0; t < SOUND_LENGTH; t++) {
wave_stereo_t* val =
(wave_stereo_t* )&wave->data.dat[t*sizeof(wave_stereo_t)];
val->left = (t % SLOPE) * ((AMPLITUDE*2)/SLOPE) - AMPLITUDE;
val->right = (t % SLOPE) * ((AMPLITUDE*2)/SLOPE) - AMPLITUDE;
}
if (fwrite((void*)wave, 1, sizeof(*wave)+DATA_SIZE, fp) <= 0) {
perror("fwrite");
}
error_close_end:
fclose(fp);
error_end:
return 0;
}
波形表示と再生
波形表示には前回に作ったバイナリ(plotwav)とgnuplotを使う。
[user@localhost sawtooth]$ gcc -o sawtooth_wave sawtooth_wave.c
[user@localhost sawtooth]$ ./sawtooth_wave sawtooth.wav
[user@localhost sawtooth]$ cd ../
[user@localhost wav]$ plot/plotwav sawtooth/sawtooth.wav > sawtooth.plt
[user@localhost wav]$ gnuplot
G N U P L O T
Version 4.6 patchlevel 2 last modified 2013-03-14
Build System: Linux x86_64
Copyright (C) 1986-1993, 1998, 2004, 2007-2013
Thomas Williams, Colin Kelley and many others
gnuplot home: http://www.gnuplot.info
faq, bugs, etc: type "help FAQ"
immediate help: type "help" (plot window: hit 'h')
Terminal type set to 'x11'
gnuplot> plot [1:10000] "sawtooth.plt" using 1:2 with lines
gnuplot>

再生してみると雑音っぽい音がでる。(下記は便宜上mp3に変換しています)
コメント