単音のみのメロディが入っているwaveファイルに伴奏をつけたいのですが具体的にどのようにすればよいのかわかりません。
自分の考えた理想としての流れは
wav読み込み→フーリエ→スペクトルの振幅を取る→その中から一番低い周波数を基本周波数とする→その周波数+45、+90のメロディを作成し、3和音にして流す。
という流れです。C,C++の経験はないため稚拙な説明になってしまいましたがご教授いただければありがたいです。
質問がありましたら何でも答えますのでよろしくお願いしたします。
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#define INFO(msg) std::cout << __LINE__ << ":" << msg << std::endl
#define PI 3.14159265359
#pragma warning(disable : 4996)
typedef struct{
unsigned int mainChunk; //文字列"RIFF"
unsigned int mainLength; //総データ長(byte)
unsigned int chunk_type; //チャンクタイプ
unsigned int subchunk; //サブチャンク内容
unsigned int subchunkLength; //サブチャンク長(byte)
unsigned short format; //通常はPCM
unsigned short mode; //チャネル数
unsigned int frequency; //サンプリング周波数(Hz)
unsigned int bitPerSec; //ビットレート
unsigned short bytePerSample; //byte/サンプル
unsigned short bitPerSample; //bit/サンプル(量子化ビット数)
unsigned int dataChunk; //文字列"data"
unsigned int dataLength; //データ長
}WAVE_HEADER;
typedef struct{
short mono;
}WAVE_LR;
int main(void){
FILE *file1;
FILE *file2;
file1=fopen("WAVE.wav","rb"); //rb=read binary
file2=fopen("EVAW.wav","wb"); //wb=write binary
FILE *fd;
fd = fopen("data.txt", "w");
WAVE_LR data;
WAVE_HEADER header;
int i;
int j=0;
int l=0;
int k=0;
fread(&header, sizeof(WAVE_HEADER), 1, file1); //&xxx=xxxを読み込む sizeof=サイズを調べる(必要サイズを確保する)
fwrite(&header, sizeof(WAVE_HEADER), 1, file2);
//読み込みデータ格納先のポインタ,読み込みデータのバイト長さ,読み込みデータの数,FILEポインタ
static const int FRAME_SIZE = 1024;
double frame[FRAME_SIZE]; // 1024サンプルずつ読み込む
double fft_frame_real[FRAME_SIZE];
double fft_frame_imag[FRAME_SIZE];
double fft_db[FRAME_SIZE];
short *sample1=new short [header.dataLength/2]; //new short [header.dataLength/2]=2byteずつ読み込むためデータ長の半分で十分
short *sample2=new short [header.dataLength/2];
for(i=0; i<(signed)header.dataLength/2; i++) //signed=符号付き(+/−)
{
fread(&data, sizeof(short),1, file1);
sample1[i]=data.mono;
}
double max[5];
double maxHz[5];
//1024サンプルごとにそれぞれの周波数の振幅がでてくる
while( fread( frame, sizeof(short), 1024, file1 )){
// フーリエ変換
for( int i = 0 ; i < FRAME_SIZE; i++ )
{
fft_frame_real[i] = 0;
fft_frame_imag[i] = 0;
for( int j = 1; j < FRAME_SIZE; j++)
{
fft_frame_real[i] += frame[j] * cos( (2*PI * i * j) / FRAME_SIZE );
fft_frame_imag[i] -= frame[j] * sin( (2*PI * i * j) / FRAME_SIZE );
}
}
//y=Asin(2πt/T)・・・・正弦波
//振幅(振幅が大きいところ上位5個を拾って見比べてどれが基本周波数か判断する)
double db = 0;
for( int i = 0; i < FRAME_SIZE; i++ )
{
fft_db[i] = 0;
for( int j = 0; j < FRAME_SIZE; j++ )
fft_db[i] += fft_frame_real[j]*fft_frame_real[j] + fft_frame_imag[j]*fft_frame_imag[j];
fft_db[i] = sqrt( fft_db[i] );
}
for(int k = 0; k < 5; k++){
fprintf( fd,"%d\n" ,fft_db );
i += 1;
}
/*新たな配列を用意してそれに基本周波数+45したのを逆フーリエ変換
例えば一番大きいのがfft_db[64]だったら、周波数は,16kHzサンプリングの場合
16000 / 1024 * 64 = 2000で2千Hzが基本周波数の倍音となる。つまり基本周波数は2000の約数の中に含まれている*/
//基本周波数を見つける
maxHz[k] = 16000 / 1024 * i;
for(int i=0; i<FRAME_SIZE; i++)
{
if( max[i] < fft_db[i] )
{
max[i] = fft_db[i];
maxHz[k] = 16000 / 1024 * i;
}
}
//基本周波数+α
/*
double l;
l = maxHz[0];
{
sin(l*2*PI) + sin{(l+45)*2*PI} + sin{(l+90)*2*PI};
}
*/
// 逆フーリエ変換
for( int i = 0 ; i < FRAME_SIZE; i++ )
{
fft_frame_real[i] = 0;
fft_frame_imag[i] = 0;
for( int j = 1; j < FRAME_SIZE; j++)
{
fft_frame_real[i] += fft_db[j] * cos( (2*PI * i * j) / FRAME_SIZE );
fft_frame_imag[i] += fft_db[j] * sin( (2*PI * i * j) / FRAME_SIZE );
}
}
}
//とった基本周波数の値をメモ帳に記録
for(i=0; i<(signed)header.dataLength/2; i++){
fwrite(&sample1[i], sizeof(short), 1, file2);
}
fclose(file1);
fclose(file2);
delete []sample1;
delete []sample2;
}
こりゃまたすごい質問だね。質問者のレベルが全然わからんw
C,C++の経験がないということだけど、他の言語の経験はあるの?あるならその言語でWAVEファイルの扱いとかフーリエ変換とかしたことある?
あと音楽の経験はあるわけ?単音のみのメロディが入っているmidiファイルに伴奏をつけて出力することは出来るの?
最後のmidiファイルの奴が出来るだけでも、有料アプリとして売って商売が出来そうだけど…
上記の返答が全部NOなら君には無理でしょう。Cの経験は無いけどアセンブラバリバリの天才プログラマーとかなら話は別だけどw
×全部NOなら
○1つでもNOなら
そうですか・・・あるのは音楽の作曲理論だけです。Cは基本的な部分を勉強中です。せめてwaveファイル内の一番低い音程がわかるように作れればいいのですが・・・
fprintf( fd,"%d\n" ,fft_db );のfft_dbの部分をmaxHzにして動かしたら基本周波数がメモ帳にでてくるとおもってたですけど振れ幅の部分がおかしいのか基本周波数の部分がおかしいのか変な値がでてきてしまいました。
その後なんとか基本周波数を取り出せましたが、周波数を変える所がなかなかうまくいきません。
>その後なんとか基本周波数を取り出せましたが
本当に?たぶん勘違いだと思うけどw
適当に取り出した値がたまたま周波数っぽい値だっただけじゃないの?
これが最後の返答だけど、wavファイルの構造はこういう風になってる。ちゃんと仕様書を読んで理解して、その通りに取り出そう。全てはそれから。
http://www.kk.iij4u.or.jp/~kondo/wave/
ツイート | ![]() |