From 15642cfc731ddb059c2c0116fb666121374e696b Mon Sep 17 00:00:00 2001 From: Shinichiro Nakamura Date: Sun, 26 Aug 2012 11:43:39 +0900 Subject: [PATCH] Added utility tools. --- soft/ffttool/Makefile | 2 + soft/ffttool/fft.c | 157 ++++++++++++++++++++++++++ soft/ffttool/fft.h | 9 ++ soft/ffttool/main.c | 47 ++++++++ soft/ffttool/sample.wav | Bin 0 -> 16044 bytes soft/ffttool/wave.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++ soft/ffttool/wave.h | 28 +++++ soft/lcdtool/main.c | 0 8 files changed, 532 insertions(+) create mode 100644 soft/ffttool/Makefile create mode 100644 soft/ffttool/fft.c create mode 100644 soft/ffttool/fft.h create mode 100644 soft/ffttool/main.c create mode 100644 soft/ffttool/sample.wav create mode 100644 soft/ffttool/wave.c create mode 100644 soft/ffttool/wave.h create mode 100644 soft/lcdtool/main.c diff --git a/soft/ffttool/Makefile b/soft/ffttool/Makefile new file mode 100644 index 0000000..0504cca --- /dev/null +++ b/soft/ffttool/Makefile @@ -0,0 +1,2 @@ +ffttool: fft.c fft.h main.c Makefile sample.wav wave.c wave.h + $(CC) -o $@ fft.c wave.c main.c -lm diff --git a/soft/ffttool/fft.c b/soft/ffttool/fft.c new file mode 100644 index 0000000..50e81ff --- /dev/null +++ b/soft/ffttool/fft.c @@ -0,0 +1,157 @@ + +#include +#include +#include "fft.h" + +/* y = fft_log2(x) */ +static int fft_log2(int x) +{ + int y; + + y = 0; + while (x > 1) { + x >>= 1; + y++; + } + + return y; +} + +/* y = 2 ^ x */ +static int fft_pow2(int x) +{ + int y; + + if (x == 0) { + y = 1; + } else { + y = 2 << (x - 1); + } + + return y; +} + +void FFT(double x_real[], double x_imag[], int N) +{ + int i, j, k, n, m, r, stage, number_of_stage, *index; + double a_real, a_imag, b_real, b_imag, c_real, c_imag, real, imag; + + /* FFT‚Ì’i” */ + number_of_stage = fft_log2(N); + + /* ƒoƒ^ƒtƒ‰ƒCŒvŽZ */ + for (stage = 1; stage <= number_of_stage; stage++) { + for (i = 0; i < fft_pow2(stage - 1); i++) { + for (j = 0; j < fft_pow2(number_of_stage - stage); j++) { + n = fft_pow2(number_of_stage - stage + 1) * i + j; + m = fft_pow2(number_of_stage - stage) + n; + r = fft_pow2(stage - 1) * j; + a_real = x_real[n]; + a_imag = x_imag[n]; + b_real = x_real[m]; + b_imag = x_imag[m]; + c_real = cos((2.0 * M_PI * r) / N); + c_imag = -sin((2.0 * M_PI * r) / N); + if (stage < number_of_stage) { + x_real[n] = a_real + b_real; + x_imag[n] = a_imag + b_imag; + x_real[m] = (a_real - b_real) * c_real - (a_imag - b_imag) * c_imag; + x_imag[m] = (a_imag - b_imag) * c_real + (a_real - b_real) * c_imag; + } else { + x_real[n] = a_real + b_real; + x_imag[n] = a_imag + b_imag; + x_real[m] = a_real - b_real; + x_imag[m] = a_imag - b_imag; + } + } + } + } + + /* ƒCƒ“ƒfƒbƒNƒX‚Ì•À‚Ñ‘Ö‚¦‚Ì‚½‚߂̃e[ƒuƒ‹‚̍쐬 */ + index = calloc(N, sizeof(int)); + for (stage = 1; stage <= number_of_stage; stage++) { + for (i = 0; i < fft_pow2(stage - 1); i++) { + index[fft_pow2(stage - 1) + i] = index[i] + fft_pow2(number_of_stage - stage); + } + } + + /* ƒCƒ“ƒfƒbƒNƒX‚Ì•À‚Ñ‘Ö‚¦ */ + for (k = 0; k < N; k++) { + if (index[k] > k) { + real = x_real[index[k]]; + imag = x_imag[index[k]]; + x_real[index[k]] = x_real[k]; + x_imag[index[k]] = x_imag[k]; + x_real[k] = real; + x_imag[k] = imag; + } + } + + free(index); +} + +void IFFT(double x_real[], double x_imag[], int N) +{ + int i, j, k, n, m, r, stage, number_of_stage, *index; + double a_real, a_imag, b_real, b_imag, c_real, c_imag, real, imag; + + /* IFFT‚Ì’i” */ + number_of_stage = fft_log2(N); + + /* ƒoƒ^ƒtƒ‰ƒCŒvŽZ */ + for (stage = 1; stage <= number_of_stage; stage++) { + for (i = 0; i < fft_pow2(stage - 1); i++) { + for (j = 0; j < fft_pow2(number_of_stage - stage); j++) { + n = fft_pow2(number_of_stage - stage + 1) * i + j; + m = fft_pow2(number_of_stage - stage) + n; + r = fft_pow2(stage - 1) * j; + a_real = x_real[n]; + a_imag = x_imag[n]; + b_real = x_real[m]; + b_imag = x_imag[m]; + c_real = cos((2.0 * M_PI * r) / N); + c_imag = sin((2.0 * M_PI * r) / N); + if (stage < number_of_stage) { + x_real[n] = a_real + b_real; + x_imag[n] = a_imag + b_imag; + x_real[m] = (a_real - b_real) * c_real - (a_imag - b_imag) * c_imag; + x_imag[m] = (a_imag - b_imag) * c_real + (a_real - b_real) * c_imag; + } else { + x_real[n] = a_real + b_real; + x_imag[n] = a_imag + b_imag; + x_real[m] = a_real - b_real; + x_imag[m] = a_imag - b_imag; + } + } + } + } + + /* ƒCƒ“ƒfƒbƒNƒX‚Ì•À‚Ñ‘Ö‚¦‚Ì‚½‚߂̃e[ƒuƒ‹‚̍쐬 */ + index = calloc(N, sizeof(int)); + for (stage = 1; stage <= number_of_stage; stage++) { + for (i = 0; i < fft_pow2(stage - 1); i++) { + index[fft_pow2(stage - 1) + i] = index[i] + fft_pow2(number_of_stage - stage); + } + } + + /* ƒCƒ“ƒfƒbƒNƒX‚Ì•À‚Ñ‘Ö‚¦ */ + for (k = 0; k < N; k++) { + if (index[k] > k) { + real = x_real[index[k]]; + imag = x_imag[index[k]]; + x_real[index[k]] = x_real[k]; + x_imag[index[k]] = x_imag[k]; + x_real[k] = real; + x_imag[k] = imag; + } + } + + /* ŒvŽZŒ‹‰Ê‚ðN‚ÅŠ„‚é */ + for (k = 0; k < N; k++) { + x_real[k] /= N; + x_imag[k] /= N; + } + + free(index); +} + diff --git a/soft/ffttool/fft.h b/soft/ffttool/fft.h new file mode 100644 index 0000000..e71c2fd --- /dev/null +++ b/soft/ffttool/fft.h @@ -0,0 +1,9 @@ + +#ifndef FFT_H +#define FFT_H + +void FFT(double x_real[], double x_imag[], int N); +void IFFT(double x_real[], double x_imag[], int N); + +#endif + diff --git a/soft/ffttool/main.c b/soft/ffttool/main.c new file mode 100644 index 0000000..9a8aa04 --- /dev/null +++ b/soft/ffttool/main.c @@ -0,0 +1,47 @@ + +#include +#include +#include "wave.h" +#include "fft.h" + +int main(int argc, char **argv) +{ + MONO_PCM pcm0; + int n, k, N; + double *x_real, *x_imag; + + if (argc != 2) { + printf("ffttool \n"); + return 1; + } + + /* WAVEƒtƒ@ƒCƒ‹‚©‚烂ƒmƒ‰ƒ‹‚̉¹ƒf[ƒ^‚ð“ü—Í‚·‚é */ + mono_wave_read(&pcm0, argv[1]); + + N = 64; + x_real = calloc(N, sizeof(double)); + x_imag = calloc(N, sizeof(double)); + + for (n = 0; n < N; n++) + { + /* x(n)‚ÌŽÀ”•” */ + x_real[n] = pcm0.s[n]; + /* x(n)‚Ì‹•”•” */ + x_imag[n] = 0.0; + } + + /* FFT‚ÌŒvŽZŒ‹‰Ê‚Íx_real‚Æx_imag‚ɏ㏑‚«‚³‚ê‚é */ + FFT(x_real, x_imag, N); + + /* Žü”g”“Á« */ + for (k = 0; k < N; k++) { + printf("%d %f+j%f\n", k, x_real[k], x_imag[k]); + } + + free(pcm0.s); + free(x_real); + free(x_imag); + + return 0; +} + diff --git a/soft/ffttool/sample.wav b/soft/ffttool/sample.wav new file mode 100644 index 0000000000000000000000000000000000000000..910a6f21e599e8b685d24026fc21843313df78dc GIT binary patch literal 16044 zcmeI&Ar69I7{>8O1BoDoz{cPj7SJG@)u53v#O6lu03Lzv2y9*i3fEw41Pg^k6R+X^ zqcAoKgOBfhp5N&hMejhm?9YeW{o!vUt(IfwNzdi_S{q%HNAf$D0wXkAtFm8C;ijJa z)GOSVQ`xN*nt>rTb3JXx_>&EJUv}!sF7LA;{%ps3YG&@|`SJen{jh$pe)9j||H=M= z{S*5~_Rq`@%umdZ%+KTp +#include +#include "wave.h" + +void mono_wave_read(MONO_PCM *pcm, char *file_name) +{ + FILE *fp; + int n; + char riff_chunk_ID[4]; + long riff_chunk_size; + char riff_form_type[4]; + char fmt_chunk_ID[4]; + long fmt_chunk_size; + short fmt_wave_format_type; + short fmt_channel; + long fmt_samples_per_sec; + long fmt_bytes_per_sec; + short fmt_block_size; + short fmt_bits_per_sample; + char data_chunk_ID[4]; + long data_chunk_size; + short data; + + fp = fopen(file_name, "rb"); + + fread(riff_chunk_ID, 1, 4, fp); + fread(&riff_chunk_size, 4, 1, fp); + fread(riff_form_type, 1, 4, fp); + fread(fmt_chunk_ID, 1, 4, fp); + fread(&fmt_chunk_size, 4, 1, fp); + fread(&fmt_wave_format_type, 2, 1, fp); + fread(&fmt_channel, 2, 1, fp); + fread(&fmt_samples_per_sec, 4, 1, fp); + fread(&fmt_bytes_per_sec, 4, 1, fp); + fread(&fmt_block_size, 2, 1, fp); + fread(&fmt_bits_per_sample, 2, 1, fp); + fread(data_chunk_ID, 1, 4, fp); + fread(&data_chunk_size, 4, 1, fp); + + pcm->fs = fmt_samples_per_sec; /* •W–{‰»Žü”g” */ + pcm->bits = fmt_bits_per_sample; /* —ÊŽq‰»¸“x */ + pcm->length = data_chunk_size / 2; /* ‰¹ƒf[ƒ^‚Ì’·‚³ */ + pcm->s = calloc(pcm->length, sizeof(double)); /* ƒƒ‚ƒŠ‚ÌŠm•Û */ + + for (n = 0; n < pcm->length; n++) + { + fread(&data, 2, 1, fp); /* ‰¹ƒf[ƒ^‚Ì“Ç‚ÝŽæ‚è */ + pcm->s[n] = (double)data / 32768.0; /* ‰¹ƒf[ƒ^‚ð-1ˆÈã1–¢–ž‚͈̔͂ɐ³‹K‰»‚·‚é */ + } + + fclose(fp); +} + +void mono_wave_write(MONO_PCM *pcm, char *file_name) +{ + FILE *fp; + int n; + char riff_chunk_ID[4]; + long riff_chunk_size; + char riff_form_type[4]; + char fmt_chunk_ID[4]; + long fmt_chunk_size; + short fmt_wave_format_type; + short fmt_channel; + long fmt_samples_per_sec; + long fmt_bytes_per_sec; + short fmt_block_size; + short fmt_bits_per_sample; + char data_chunk_ID[4]; + long data_chunk_size; + short data; + double s; + + riff_chunk_ID[0] = 'R'; + riff_chunk_ID[1] = 'I'; + riff_chunk_ID[2] = 'F'; + riff_chunk_ID[3] = 'F'; + riff_chunk_size = 36 + pcm->length * 2; + riff_form_type[0] = 'W'; + riff_form_type[1] = 'A'; + riff_form_type[2] = 'V'; + riff_form_type[3] = 'E'; + + fmt_chunk_ID[0] = 'f'; + fmt_chunk_ID[1] = 'm'; + fmt_chunk_ID[2] = 't'; + fmt_chunk_ID[3] = ' '; + fmt_chunk_size = 16; + fmt_wave_format_type = 1; + fmt_channel = 1; + fmt_samples_per_sec = pcm->fs; /* •W–{‰»Žü”g” */ + fmt_bytes_per_sec = pcm->fs * pcm->bits / 8; + fmt_block_size = pcm->bits / 8; + fmt_bits_per_sample = pcm->bits; /* —ÊŽq‰»¸“x */ + + data_chunk_ID[0] = 'd'; + data_chunk_ID[1] = 'a'; + data_chunk_ID[2] = 't'; + data_chunk_ID[3] = 'a'; + data_chunk_size = pcm->length * 2; + + fp = fopen(file_name, "wb"); + + fwrite(riff_chunk_ID, 1, 4, fp); + fwrite(&riff_chunk_size, 4, 1, fp); + fwrite(riff_form_type, 1, 4, fp); + fwrite(fmt_chunk_ID, 1, 4, fp); + fwrite(&fmt_chunk_size, 4, 1, fp); + fwrite(&fmt_wave_format_type, 2, 1, fp); + fwrite(&fmt_channel, 2, 1, fp); + fwrite(&fmt_samples_per_sec, 4, 1, fp); + fwrite(&fmt_bytes_per_sec, 4, 1, fp); + fwrite(&fmt_block_size, 2, 1, fp); + fwrite(&fmt_bits_per_sample, 2, 1, fp); + fwrite(data_chunk_ID, 1, 4, fp); + fwrite(&data_chunk_size, 4, 1, fp); + + for (n = 0; n < pcm->length; n++) + { + s = (pcm->s[n] + 1.0) / 2.0 * 65536.0; + + if (s > 65535.0) + { + s = 65535.0; /* ƒNƒŠƒbƒsƒ“ƒO */ + } + else if (s < 0.0) + { + s = 0.0; /* ƒNƒŠƒbƒsƒ“ƒO */ + } + + data = (short)(s + 0.5) - 32768; /* ŽlŽÌŒÜ“ü‚ƃIƒtƒZƒbƒg‚Ì’²ß */ + fwrite(&data, 2, 1, fp); /* ‰¹ƒf[ƒ^‚̏‘‚«o‚µ */ + } + + fclose(fp); +} + +void stereo_wave_read(STEREO_PCM *pcm, char *file_name) +{ + FILE *fp; + int n; + char riff_chunk_ID[4]; + long riff_chunk_size; + char riff_form_type[4]; + char fmt_chunk_ID[4]; + long fmt_chunk_size; + short fmt_wave_format_type; + short fmt_channel; + long fmt_samples_per_sec; + long fmt_bytes_per_sec; + short fmt_block_size; + short fmt_bits_per_sample; + char data_chunk_ID[4]; + long data_chunk_size; + short data; + + fp = fopen(file_name, "rb"); + + fread(riff_chunk_ID, 1, 4, fp); + fread(&riff_chunk_size, 4, 1, fp); + fread(riff_form_type, 1, 4, fp); + fread(fmt_chunk_ID, 1, 4, fp); + fread(&fmt_chunk_size, 4, 1, fp); + fread(&fmt_wave_format_type, 2, 1, fp); + fread(&fmt_channel, 2, 1, fp); + fread(&fmt_samples_per_sec, 4, 1, fp); + fread(&fmt_bytes_per_sec, 4, 1, fp); + fread(&fmt_block_size, 2, 1, fp); + fread(&fmt_bits_per_sample, 2, 1, fp); + fread(data_chunk_ID, 1, 4, fp); + fread(&data_chunk_size, 4, 1, fp); + + pcm->fs = fmt_samples_per_sec; /* •W–{‰»Žü”g” */ + pcm->bits = fmt_bits_per_sample; /* —ÊŽq‰»¸“x */ + pcm->length = data_chunk_size / 4; /* ‰¹ƒf[ƒ^‚Ì’·‚³ */ + pcm->sL = calloc(pcm->length, sizeof(double)); /* ƒƒ‚ƒŠ‚ÌŠm•Û */ + pcm->sR = calloc(pcm->length, sizeof(double)); /* ƒƒ‚ƒŠ‚ÌŠm•Û */ + + for (n = 0; n < pcm->length; n++) + { + fread(&data, 2, 1, fp); /* ‰¹ƒf[ƒ^iLƒ`ƒƒƒ“ƒlƒ‹j‚Ì“Ç‚ÝŽæ‚è */ + pcm->sL[n] = (double)data / 32768.0; /* ‰¹ƒf[ƒ^‚ð-1ˆÈã1–¢–ž‚͈̔͂ɐ³‹K‰»‚·‚é */ + + fread(&data, 2, 1, fp); /* ‰¹ƒf[ƒ^iRƒ`ƒƒƒ“ƒlƒ‹j‚Ì“Ç‚ÝŽæ‚è */ + pcm->sR[n] = (double)data / 32768.0; /* ‰¹ƒf[ƒ^‚ð-1ˆÈã1–¢–ž‚͈̔͂ɐ³‹K‰»‚·‚é */ + } + + fclose(fp); +} + +void stereo_wave_write(STEREO_PCM *pcm, char *file_name) +{ + FILE *fp; + int n; + char riff_chunk_ID[4]; + long riff_chunk_size; + char riff_form_type[4]; + char fmt_chunk_ID[4]; + long fmt_chunk_size; + short fmt_wave_format_type; + short fmt_channel; + long fmt_samples_per_sec; + long fmt_bytes_per_sec; + short fmt_block_size; + short fmt_bits_per_sample; + char data_chunk_ID[4]; + long data_chunk_size; + short data; + double s; + + riff_chunk_ID[0] = 'R'; + riff_chunk_ID[1] = 'I'; + riff_chunk_ID[2] = 'F'; + riff_chunk_ID[3] = 'F'; + riff_chunk_size = 36 + pcm->length * 4; + riff_form_type[0] = 'W'; + riff_form_type[1] = 'A'; + riff_form_type[2] = 'V'; + riff_form_type[3] = 'E'; + + fmt_chunk_ID[0] = 'f'; + fmt_chunk_ID[1] = 'm'; + fmt_chunk_ID[2] = 't'; + fmt_chunk_ID[3] = ' '; + fmt_chunk_size = 16; + fmt_wave_format_type = 1; + fmt_channel = 2; + fmt_samples_per_sec = pcm->fs; /* •W–{‰»Žü”g” */ + fmt_bytes_per_sec = pcm->fs * pcm->bits / 8 * 2; + fmt_block_size = pcm->bits / 8 * 2; + fmt_bits_per_sample = pcm->bits; /* —ÊŽq‰»¸“x */ + + data_chunk_ID[0] = 'd'; + data_chunk_ID[1] = 'a'; + data_chunk_ID[2] = 't'; + data_chunk_ID[3] = 'a'; + data_chunk_size = pcm->length * 4; + + fp = fopen(file_name, "wb"); + + fwrite(riff_chunk_ID, 1, 4, fp); + fwrite(&riff_chunk_size, 4, 1, fp); + fwrite(riff_form_type, 1, 4, fp); + fwrite(fmt_chunk_ID, 1, 4, fp); + fwrite(&fmt_chunk_size, 4, 1, fp); + fwrite(&fmt_wave_format_type, 2, 1, fp); + fwrite(&fmt_channel, 2, 1, fp); + fwrite(&fmt_samples_per_sec, 4, 1, fp); + fwrite(&fmt_bytes_per_sec, 4, 1, fp); + fwrite(&fmt_block_size, 2, 1, fp); + fwrite(&fmt_bits_per_sample, 2, 1, fp); + fwrite(data_chunk_ID, 1, 4, fp); + fwrite(&data_chunk_size, 4, 1, fp); + + for (n = 0; n < pcm->length; n++) + { + s = (pcm->sL[n] + 1.0) / 2.0 * 65536.0; + + if (s > 65535.0) + { + s = 65535.0; /* ƒNƒŠƒbƒsƒ“ƒO */ + } + else if (s < 0.0) + { + s = 0.0; /* ƒNƒŠƒbƒsƒ“ƒO */ + } + + data = (short)(s + 0.5) - 32768; /* ŽlŽÌŒÜ“ü‚ƃIƒtƒZƒbƒg‚Ì’²ß */ + fwrite(&data, 2, 1, fp); /* ‰¹ƒf[ƒ^iLƒ`ƒƒƒ“ƒlƒ‹j‚̏‘‚«o‚µ */ + + s = (pcm->sR[n] + 1.0) / 2.0 * 65536.0; + + if (s > 65535.0) + { + s = 65535.0; /* ƒNƒŠƒbƒsƒ“ƒO */ + } + else if (s < 0.0) + { + s = 0.0; /* ƒNƒŠƒbƒsƒ“ƒO */ + } + + data = (short)(s + 0.5) - 32768; /* ŽlŽÌŒÜ“ü‚ƃIƒtƒZƒbƒg‚Ì’²ß */ + fwrite(&data, 2, 1, fp); /* ‰¹ƒf[ƒ^iRƒ`ƒƒƒ“ƒlƒ‹j‚̏‘‚«o‚µ */ + } + + fclose(fp); +} + diff --git a/soft/ffttool/wave.h b/soft/ffttool/wave.h new file mode 100644 index 0000000..8e5471f --- /dev/null +++ b/soft/ffttool/wave.h @@ -0,0 +1,28 @@ + +#ifndef WAVE_H +#define WAVE_H + +typedef struct +{ + int fs; /* 標本化周波数 */ + int bits; /* 量子化精度 */ + int length; /* 音データの長さ */ + double *s; /* 音データ */ +} MONO_PCM; + +typedef struct +{ + int fs; /* 標本化周波数 */ + int bits; /* 量子化精度 */ + int length; /* 音データの長さ */ + double *sL; /* 音データ(Lチャンネル) */ + double *sR; /* 音データ(Rチャンネル) */ +} STEREO_PCM; + +void mono_wave_read(MONO_PCM *pcm, char *file_name); +void mono_wave_write(MONO_PCM *pcm, char *file_name); +void stereo_wave_read(STEREO_PCM *pcm, char *file_name); +void stereo_wave_write(STEREO_PCM *pcm, char *file_name); + +#endif + diff --git a/soft/lcdtool/main.c b/soft/lcdtool/main.c new file mode 100644 index 0000000..e69de29 -- 2.11.0