掲示板システム
ホーム
アクセス解析
カテゴリ
ログアウト
waveファイルに含まれている音の音程を変化させるには? (ID:63627)
名前
ホームページ(ブログ、Twitterなど)のURL (省略可)
本文
単音のみのメロディが入っている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; }
←解決時は質問者本人がここをチェックしてください。
更新する
戻る
掲示板システム
Copyright 2021 Takeshi Okamoto All Rights Reserved.