コアダンプの数だけ強くなれるよ

見習いエンジニアの備忘log

WAVEファイルのノコギリ波を作って再生してみる


前回はWAVEファイルからデータを抽出し波形をプロットしてグラフ化した。

www.segmentation-fault.xyz



今回は逆にWAVEファイルを作成してちゃんと再生できるか試してみる。


ノコギリ波の作成


下記条件でノコギリ波を作成する。

# 構成要素
1 振幅 15000(レンジは-15000~15000)
2 振動数 50Hz
3 サンプリング周波数 44.1kHz
4 再生時間 3秒
5 チャンネル数 2(ステレオ)
6 量子化精度 16bit


上記ノコギリ波のサンプリング時刻 t における値 S(t) を式にすると次の通りになる。

 S(t) = (t \bmod (サンプリング周波数/振動数)) × ( (振幅×2)/(サンプリング周波数/振動数)) - 振幅


(サンプリング周波数/振動数)はノコギリ波の傾きを表す。

ノコギリ波生成プログラム


前回のソースを流用して下記の通り作成した。

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>


f:id:segmentation-fault:20170807232013p:plain



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