ページ 11

VC++でデジタルフィルタ

Posted: 2013年1月11日(金) 14:02
by undergo
VC++2008proでデジタルフィルタを作成しています。
GetFrq関数で生成した音にエフェクトをかけて再生することはできたのですが、
fopenを使用してバイナリファイルにエフェクトをかけることができません。
ファイルオープンの方法に問題があると思うのですが特定できません。
問題個所分かる人がいればお願いします。

コード:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
//#include <afx.h>
#pragma comment(linker,"/subsystem:windows")
#pragma comment(linker,"/NODEFAULTLIB")
#pragma comment(lib,"winmm.lib")//winmm.libをリンクする

#ifdef __cplusplus
extern "C" { 
#endif
	int _fltused=1; 
	void _cdecl _check_commonlanguageruntime_version(){}

	int __cdecl _ftol2_sse() {
		int integral;
		short oldfcw, newfcw;
		__asm {
			fstcw [oldfcw]
			mov ax,[oldfcw]
			or ax,0c00h ; chop
			mov [newfcw],ax
			fldcw [newfcw]
			fistp dword ptr[integral]
			fldcw [oldfcw]
		}
		return integral;
	}
	
	int __cdecl _ftol2() {return _ftol2_sse();}
#ifdef __cplusplus
}
#endif

/*
float GetFrq(char c)
{
	switch(c){
		case 'a': return 440*0.5946f;//ド  440*2^( 3/12)
		case 's': return 440*0.6674f;//レ  440*2^( 5/12)
		case 'd': return 440*0.7492f;//ミ  440*2^( 7/12)
		case 'f': return 440*0.8409f;//ファ440*2^( 8/12)
		case 'g': return 440*0.8909f;//ソ  440*2^(10/12)
		case 'h': return 440*1.0f;   //ラ  440*2^(12/12)
		case 'j': return 440*1.1225f;//シ  440*2^(12/12)
		case 'k': return 440*1.1892f;//ド  440*2^(15/12)
		case 'a2': return 440*0.5946f;//ド  440*2^( 3/12)
		case 's2': return 440*0.6674f;//レ  440*2^( 5/12)
		case 'd2': return 440*0.7492f;//ミ  440*2^( 7/12)
		case 'f2': return 440*0.8409f;//ファ440*2^( 8/12)
		case 'g2': return 440*0.8909f;//ソ  440*2^(10/12)
		case 'h2': return 440*1.0f;   //ラ  440*2^(12/12)
		case 'j2': return 440*1.1225f;//シ  440*2^(12/12)
		case 'k2': return 440*1.1892f;//ド  440*2^(15/12)
	}
	return 0;
}
*/

void WinMainCRTStartup()
{
//	char* music = "asdfghjka2s2d2f2g2h2j2k2";//楽譜データ(ここを変えると、なる音が変わります)
//	int = fp;
	FILE  *fp;
	char music[1000];
	long t, n = 0;

//	const char filename[] = "TITLE 003.wav";
//	const char mode[] = "wb";
	float pm = 0.5f;//1つあたりの音符の時間(秒)

	if((fp = fopen("\\FILE\\Redirect$\\Student\\523\\52329\\Desktop\\TITLE 003.wav", "wb")) == NULL)
	{
		printf("ファイルの書込みに失敗しました.\n");
		exit(1);
	}
	else
	{
		fp = fopen("\\FILE\\Redirect$\\Student\\523\\52329\\Desktop\\TITLE 003.wav", "wb");
	}

	fscanf(fp, "%f", &(music[n]));
	
/*
	//波形生成
	long musictime = (long)(lstrlen(music)*44100);//1[sec] = 44100[sample] サンプリングレート44.1kHz
	short* wave_data=(short*)GlobalAlloc(GPTR,sizeof(short)*musictime);
	long ptime = (long)(44100*pm);
*/
/*
	char* music_ptr = music - 1;//ひとつ手前にしておく
	for(t=0; t<musictime; t++){
		long p = t%(ptime);
		if(p==0) music_ptr++;//次の音符

		float frq = GetFrq(*music_ptr);//周波数を得る
		long fdtime = (long)(44100/frq);//周波数をサンプル時間に変換
		if( (p%fdtime)<(fdtime/2) ) wave_data[t] =  12767;  //方形波生成
		else					    wave_data[t] = -12767;
	}
*/


	long musictime = (long)(lstrlen(music));

	short* wave_data=(short*)GlobalAlloc(GPTR,sizeof(short)*musictime);


	short* in = (short*)music;
	//-------filter----------------------------------------------------
	float* out=(float*)GlobalAlloc(GPTR,sizeof(float)*(char)music);

	long filter = 0;//フィルターの種類を選択

	switch(filter){
		case 0:{
			//ディレイ
			const int DELAY_TIME	= 8000;
			const float DELAY_LEVEL = 0.4f;
			for(t=0; t<musictime;  t++){
				if(t>=DELAY_TIME) out[t] = in[t] + out[t-DELAY_TIME]*DELAY_LEVEL;	//ディレイの出力信号 = 入力信号 + 読み出したバッファの値
				else              out[t] = in[t];
			}
		}break;
		case 1:{
			//ローパス
			const float LOW_PASS	= 0.80f;
			for(t=1; t<musictime;  t++){  
				out[t] = in[t] + (out[t-1]-in[t])*LOW_PASS;
			}
		}break;
		case 2:{
			//ハイパス
			const float HIGH_PASS	= 0.80f;
			for(t=1; t<musictime;  t++){
				out[t] = in[t] - in[t-1]*HIGH_PASS;
			}
		}break;

/*
		case 3:{
			//レゾナンス
			const float RESO		= 0.1f;
			const float LOW_PASS	= 0.8f;
			float v0=0,v1=0;
			for(t=1; t<musictime;  t++){
				v0 =  (1.0f - RESO*LOW_PASS)*v0 + (in[t]-v1)*LOW_PASS;
				v1 =  (1.0f - RESO*LOW_PASS)*v1 +  LOW_PASS*v0;
				out[t] = v1;
			}

		}break;
*/

	}


	//出力
	for(t=0; t<musictime;  t++){
		if(out[t]> 32767.0f) out[t] =  32767.0f;
		if(out[t]<-32767.0f) out[t] = -32767.0f;
		wave_data[t] = (short)out[t];
	}

	fclose(fp);

	//-----------------------------------------------------------------

	//WAVEデバイス設定
	WAVEFORMATEX wf;                              //WAVEFORMATEX 構造体
	wf.wFormatTag=WAVE_FORMAT_PCM;                //これはこのまま
	wf.nChannels=1;                               //モノラル ステレオなら'2'
	wf.nSamplesPerSec=44100;                      //44100Hz
	wf.wBitsPerSample=16;                         //16ビット
	wf.nBlockAlign=wf.nChannels*wf.wBitsPerSample/8;       //計算
	wf.nAvgBytesPerSec=wf.nSamplesPerSec*wf.nBlockAlign;   //計算
	wf.cbSize=0;                                           //計算
	HWAVEOUT hWOut;
	waveOutOpen(&hWOut, WAVE_MAPPER, &wf, 0, 0, CALLBACK_NULL);
	
	//WAVE情報設定
	WAVEHDR wh;
	wh.lpData = (LPSTR)wave_data;
	wh.dwBufferLength = sizeof(short)*musictime;
	wh.dwFlags = 0;
	wh.dwLoops = 1;//1回だけ再生
	wh.dwBytesRecorded=0;
	wh.dwUser=0;
	wh.lpNext=NULL;
	wh.reserved=0;

	//再生
	waveOutPrepareHeader(hWOut , &wh , sizeof(WAVEHDR));
	waveOutWrite(hWOut , &wh , sizeof(WAVEHDR));
 
	MessageBox(NULL,"WavePlay","Wave",MB_OK);

	ExitProcess(0);
}


Re: VC++でデジタルフィルタ

Posted: 2013年1月11日(金) 15:25
by softya(ソフト屋)
バイナリファイルにfscanfしていませんか?
fscanfはテキスト以外に使ってはいけませんよ。
使うならfreadです。

「wav ファイルフォーマット」
http://www.kk.iij4u.or.jp/~kondo/wave/
「WAVEファイルの読込み/再生」
http://akigamyl.web.fc2.com/Clang/wavread.html

ちなみにVC++は開発環境名で言語の名前ではありませんので、環境と言語の説明としては中途半端ですので次回はもう少し詳しくお願いします。
今回の場合は次のように書くべきかと思います。
開発環境 VisualStudio2008Pro
言語 C言語
ライブラリ/API MCI

Re: VC++でデジタルフィルタ

Posted: 2013年1月11日(金) 15:31
by softya(ソフト屋)
あっと、もう一つ
WinMainCRTStartup
を自分で書いてはいけません。

設定を変更して普通のmainで動くように書き換えてください。
何処を参考にしたのか知りませんが行儀の悪い書き方でオススメしません。