/* 音姫録音機 main sub 1995 6 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <file_dlg.h>
#include <egb.h>
#include <mos.h>
#include <snd.h>
#include <wav.h>
#include <math.h>
#include "wavhime.h"
#include "otolib.h"

/* about */
int	alertId = -1 ;
int	messageId[3] = -1 ;
int	dspIconId = -1 ;
int	aboutOKBtnId = -1 ;

/* information */
int	infDialogId = -1 ;
int	infMsgId[7] = -1 ;
int	infNumId[5] = -1 ;
int	infOkBtnId = -1 ;

/* desk */
int	baseDialogId = -1 ;
int	baseDialogId2 = -1 ;
int	mainMesId[4] = -1 ;
int	recLineVolumeId = -1 ;
int	recCdVolumeId = -1 ;
int	recMicVolumeId = -1 ;
int	recLineNumId = -1 ;
int	recCdNumId = -1 ;
int	recMicNumId = -1 ;
int	menubarId = -1 ;
int	menuId = -1 ;
int	mItemId[3] = -1 ;
int	SDKmenuId = -1 ;
int	SDKmItemId[3] = -1 ;
int	quitIconId = -1 ;
int	mainModeMesId = -1 ;
int	fftSubDialogId = -1 ;
int	fftMesId[59] = -1 ;
int	fftChBtnId[2] = -1 ;
int	fftSubDialogId2 = -1 ;
int	fftWaveBaseMesId = -1 ;
int	fftScaleMesId = -1 ;
int	fftMulNumId = -1 ;
int	fftMulScrId = -1 ;
int	fftSubDialogId3 = -1 ;
int	fftFreqMesId[2] = -1 ;
int	fftSpecBaseMesId = -1 ;
int	fftWinBtnId[4] = -1 ;
int	fftNBtnId[3] = -1 ;
int	fftFreqBtnId[3] = -1 ;
int	fftOkBtnId = -1 ;
int	fftCanBtnId = -1 ;
int	fftSmpFreqBtnId[3] = -1 ;

/* error */
int	errorId = -1 ;
int	errorOKBtnId = -1 ;
int	errorIconId = -1 ;
int	errormessage[2] = -1 ;

/* rec */
int	recDialogId = -1 ;
int	recSubDialogId = -1 ;
int	recTimeNumId = -1 ;
int	recMesId[17] = -1 ;
int	recFreqBtnId[3] = -1 ;
int	recFreqMesId[3] = -1 ;
int	recChanBtnId[2] = -1 ;
int	recChanMesId[2] = -1 ;
int	recBitBtnId[2] = -1 ;
int	recBitMesId[2] = -1 ;
int	recSubDialogId1 = -1 ;
int	recOkBtnId = -1 ;
int	recCanBtnId = -1 ;
int	recSubDialogId2 = -1 ;
int	recPlayBtnId = -1 ;
int	recStopBtnId = -1 ;
int	recPlayBarId = -1 ;
int	recSubDialogId3 = -1 ;
int	recInfBtnId = -1 ;


char sndFileName[100] = "\0" ;

	/* 各コマンド呼び出し */

/* 各種ボリュームの設定 */
int	recVolumeSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int	var, min, max, len, page, s ;
	int	var2, min2, max2, delta2, ptColumn2 ;

	MMI_SendMessage( kobj, MM_GETSCROLL, 5,
										&var, &min, &max, &len, &page ) ;

	if( kobj == recLineVolumeId )	/* ライン入力 */
	{
		MMI_SendMessage( recLineNumId, MM_GETNUMBOX, 5,
							&var2, &min2, &max2, &delta2, &ptColumn2 ) ;
		MMI_SendMessage( recLineNumId, MM_SETNUMBOX, 5,
							var, min2, max2, delta2, ptColumn2 ) ;
		MMI_SendMessage( recLineNumId, MM_SHOW, 0 ) ;
		SND_elevol_set( 0, var, var );		/* line volume set */
		if( var == 0 )
		{
			SND_get_elevol_mute( &s ) ;
			SND_elevol_mute( s & 0xfffffff3 ) ;
		}
	}

	if( kobj == recCdVolumeId )		/* CD */
	{
		MMI_SendMessage( recCdNumId, MM_GETNUMBOX, 5,
							&var2, &min2, &max2, &delta2, &ptColumn2 ) ;
		MMI_SendMessage( recCdNumId, MM_SETNUMBOX, 5,
							var, min2, max2, delta2, ptColumn2 ) ;
		MMI_SendMessage( recCdNumId, MM_SHOW, 0 ) ;
		SND_elevol_set( 1, var, var );		/* cd volume set */
		if( var == 0 )
		{
			SND_get_elevol_mute( &s ) ;
			SND_elevol_mute( s & 0xffffffcf ) ;
		}
	}

	if( kobj == recMicVolumeId )	/* マイク */
	{
		MMI_SendMessage( recMicNumId, MM_GETNUMBOX, 5,
							&var2, &min2, &max2, &delta2, &ptColumn2 ) ;
		MMI_SendMessage( recMicNumId, MM_SETNUMBOX, 5,
							var, min2, max2, delta2, ptColumn2 ) ;
		MMI_SendMessage( recMicNumId, MM_SHOW, 0 ) ;
		SND_elevol_set( 2, var, var );		/* mic volume set */
		if( var == 0 )
		{
			SND_get_elevol_mute( &s ) ;
			SND_elevol_mute( s & 0xffffffbf ) ;
		}
	}

	return NOERR ;
}

/* ファイル */

/*	initDataIRCDSK:mItemId[1]:MJ_MITEML40の呼び出し関数	*/
int	recFileFunc(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	fileSet() ;
	return NOERR ;
}

static int fileSet()
{
	char name[100] ;
	char *ExtStr[] = { "*.WAV", NULL } ;
	int ret ;

	/* name , kakuchou[拡張子(.***)] → fullname = name + kakuchou */
	file_kakuchousi_set( name, sndFileName, ".WAV" ) ;
	ret = fileSelecter( name, ExtStr,
							"ファイル", "実  行", "取  消");

	if( ret == NOERR )
	{
		/* name , kakuchou[拡張子(.***)] → fullname = name + kakuchou */
		file_kakuchousi_set( sndFileName, name, ".WAV" ) ;
	}

	return ret ;
}

/* モード切替え */

static int mainMode = 0 ;

/*	initDataIRCDSK:mItemId[2]:MJ_MITEML40の呼び出し関数	*/
int	recPlayFunc(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	if( mainMode == 0 )
	{
		sndEffectFftEnd() ;
		sndRecStart() ;

		if( sndFileName[0] == 0 )
		{
			fileSet() ;
		}

		mainMode = 1 ;
		MMI_SendMessage( mainModeMesId , MM_SETMSG , 1 ,
				"ただいまのモード : 録音＆再生モード" ) ;
		MMI_SendMessage( mItemId[2] , MM_SETMSG , 1 ,
				"   波形解析 " ) ;
		MMI_SendMessage( menubarId, MM_SHOW, 0 ) ;
	}
	else
	{
		sndRecEnd() ;
		sndEffectFftStart() ;
		mainMode = 0 ;
		MMI_SendMessage( mainModeMesId , MM_SETMSG , 1 ,
			"ただいまのモード : 波形解析モード" ) ;
			MMI_SendMessage( mItemId[2] , MM_SETMSG , 1 ,
				"  録音＆再生" ) ;
		MMI_SendMessage( menubarId, MM_SHOW, 0 ) ;
	}

	return NOERR ;
}

/*	REC */

static int recFreqMode = 0 ;
static int recChanMode = 0 ;
static int recBitMode  = 0 ;
static int recCapacity ;
//static int recAlertobj ;  /*  ALERTOBJ退避  */

int	sndRecStart()
{
	int var, min, max, delta, ptColumn ;
	int i ;

    WAV_getCapability( &recCapacity, 22050 ) ; 
    if ( recCapacity & WAV_CAP_16PCM_EXIST )
    {                              //  16ビットPCMによるサンプリング
		MTL_resetAtrObj( recFreqBtnId[0], (~MS_DSPONLYL40) ) ;

		MTL_resetAtrObj( recChanBtnId[0], (~MS_DSPONLYL40) ) ;

		MTL_resetAtrObj( recBitBtnId[0], (~MS_DSPONLYL40) ) ;
    }
    else
    {                             //  内蔵PCMによるサンプリング
		MTL_resetAtrObj( recFreqBtnId[0], (~MS_DSPONLYL40) ) ;
		MTL_setAtrObj( recFreqBtnId[0], MS_INACTIVEL40 ) ;

		MTL_resetAtrObj( recChanBtnId[0], (~MS_DSPONLYL40) ) ;
		MTL_setAtrObj( recChanBtnId[0], MS_INACTIVEL40 ) ;

		MTL_resetAtrObj( recBitBtnId[0], (~MS_DSPONLYL40) ) ;
		MTL_setAtrObj( recBitBtnId[0], MS_INACTIVEL40 ) ;

		MMI_SendMessage( recCanBtnId, MM_DETACH, 0 ) ; // stopﾎﾞﾀﾝ削除
		MMI_SendMessage( recMesId[2], MM_DETACH, 0 ) ; // stopﾎﾞﾀﾝ表示削除

		if( recFreqMode == 0 )recFreqMode = 1 ;
		recChanMode = 1 ;
		recBitMode = 1 ;
    }

	/* ボタンセット */
	for( i=0 ; i<3 ; i++ )
		MTL_resetFlagObj( recFreqBtnId[i], (~(MS_UNSELECT | MS_TOGGLE)) ) ;
	MTL_setFlagObj( recFreqBtnId[recFreqMode], (MS_UNSELECT | MS_TOGGLE) ) ;

	for( i=0 ; i<2 ; i++ )
		MTL_resetFlagObj( recChanBtnId[i], (~(MS_UNSELECT | MS_TOGGLE)) ) ;
	MTL_setFlagObj( recChanBtnId[recChanMode], (MS_UNSELECT | MS_TOGGLE) ) ;

	for( i=0 ; i<2 ; i++ )
		MTL_resetFlagObj( recBitBtnId[i], (~(MS_UNSELECT | MS_TOGGLE)) ) ;
	MTL_setFlagObj( recBitBtnId[recBitMode], (MS_UNSELECT | MS_TOGGLE) ) ;


	MMI_SendMessage( recDialogId, MM_ATTACH, 1, baseDialogId2 ) ;

	MMI_SendMessage( recDialogId, MM_SHOW, 0 ) ;	/* 全体を見せる */

	return NOERR ;
}

int	sndRecEnd()
{
	MMI_SendMessage( recDialogId, MM_ERASE, 0 ) ;
	MMI_SendMessage( recDialogId, MM_DETACH, 0 ) ;

	return NOERR ;
}

/* 録音時間 */
int	recTimeSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	return NOERR ;
}

/*	initDataIWVREC:recFreqBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVREC:recFreqBtnId[1]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVREC:recFreqBtnId[2]:MJ_TICONL40の呼び出し関数	*/
int	recFreqSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<3 ; i++ )
	{
		if( kobj == recFreqBtnId[i] )
		{
			MTL_setFlagObj( recFreqBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( recFreqBtnId[recFreqMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( recFreqBtnId[recFreqMode], MM_SHOW, 0 ) ;
			recFreqMode = i ;
		}
	}
	return NOERR ;
}

/*	initDataIWVREC:recChanBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVREC:recChanBtnId[1]:MJ_TICONL40の呼び出し関数	*/
int	recChanSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<2 ; i++ )
	{
		if( kobj == recChanBtnId[i] )
		{
			MTL_setFlagObj( recChanBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( recChanBtnId[recChanMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( recChanBtnId[recChanMode], MM_SHOW, 0 ) ;
			recChanMode = i ;
		}
	}
	return NOERR ;
}

/*	initDataIWVREC:recBitBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVREC:recBitBtnId[1]:MJ_TICONL40の呼び出し関数	*/
int	recBitSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<4 ; i++ )
	{
		if( kobj == recBitBtnId[i] )
		{
			MTL_setFlagObj( recBitBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( recBitBtnId[recBitMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( recBitBtnId[recBitMode], MM_SHOW, 0 ) ;
			recBitMode = i ;
		}
	}
	return NOERR ;
}














/* 実行 */

static int recMode = 0 ;

int	recOkchk(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int ret ;
	int alertobj ;

	if( recMode == 0 )
	{
		alertobj = MMI_GetAlertObj() ;  /*  現在のALERTOBJを退避  　  */
		MMI_SetAlertObj( recSubDialogId1 ) ;
		setMsgColor( recMesId[0], EXE_COLOR ) ;

		recMode = 1 ;
		ret = sndRecExec() ;
		recMode = 0 ;

		setMsgColor( recMesId[0], MOJI_COLOR ) ;

		if( ret )
			errorCheck( ret ) ;

		MMI_SetAlertObj( alertobj ) ;  /*  ALERTOBJを元に戻す    　   */
		MMI_FlushEvnt() ;	/* イベントをフラッシュ */
	}
	return NOERR ;
}

/* 取消 */
int	recCanchk(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	if( recMode == 1 )
	{
		recMode = -1 ;
	}
	return NOERR ;
}


//  変数定義
static int recordingFreq = 44100 ;          //  サンプリング周波数
static int recordingKind = 2 ;              //  データ種別（＝モノラル）
static int recordingBitN = 16 ;                      //  サンプリングビット数
static int recordingPcmSize = 44100 * (16/8) * 10 ;  //  サンプリングデータ長

/* 録音実行ルーチン */
int sndRecExec()
{
	int	var, min, max, delta, ptColumn ;
	int ret ;

	switch( recFreqMode )
	{
	case 0:
		recordingFreq = 44100 ;
		break ;
	case 1:
		recordingFreq = 22050 ;
		break ;
	case 2:
		recordingFreq = 11025 ;
		break ;
	}
	if( recChanMode == 0 )
		recordingKind = 2 ;
	else
		recordingKind = 1 ;
	if( recBitMode == 0 )
		recordingBitN = 16 ;
	else
		recordingBitN = 8 ;

	MMI_SendMessage( recTimeNumId, MM_GETNUMBOX, 5,	/* 録音時間抽出 */
							&var, &min, &max, &delta, &ptColumn ) ;
	recordingPcmSize = recordingFreq * (recordingBitN/8) * recordingKind * var / 10 ;

    if ( recCapacity & WAV_CAP_16PCM_EXIST )
    {                              //  16ビットPCMによるサンプリング
		ret = recfile() ;
	}
	else
    {                              //  8ビットPCMによるサンプリング
		ret = recmemory() ;
	}

	return ret ;
}

static int rec_n_count ;

//  同期関数
//  注意：この同期関数のアドレスが０の場合、NULL指定と誤判断されるので、
//        この関数の位置には注意が必要
static void  recSyncfunc()
{
      rec_n_count ++ ;
      return ;
}

//  直接ファイルへ１６ＫＢ毎にサンプリングデータを書き込む
static int recfile()
{
    FILE  *pFile ;                //  ファイルポインタ
    char  *pring ;                //  リングバッファポインタ
    char  head[256] ;
    struct  buf_ctrl
    {
        int   sum ;
        int   apply_loc ;
        int   system_loc ;
        struct
        {
            char  *ptr ;
            char  reserve[8] ;
        }   buftbl[2] ;
    }   *pctrl ;                 //  リングバッファ管理テーブルポインタ
    int   cap ;                   //  性能情報
    int   ch, x, y ;              //  マウス用変数
    int   pcmstart ;              //  PCMデータ相対開始位置
    int   wrtsz ;                 //  書き込むデータサイズ
    int   wrtsize ;               //  書き込まれたデータサイズ
    int   remain ;                //  残りサンプリングデータサイズ
    int   fl = 0 ;                //  無限ループフラグ
    int   status ;                //  ステータス
    int   nextloc ;               //  次回のアプリケーション位置
    int   error ;
    int   total ;

	error = NOERR ;

    WAV_getCapability( &cap, recordingFreq ) ; 
    if ( !( cap & WAV_CAP_16PCM_EXIST ) )
    {
        return NOERR ;
    }

      //  リングバッファとリングバッファ管理テーブルの領域の確保を行う
      //  リングバッファ数は16個
/*
    if ( (pring = TL_malloc( (16+1)*4096 )) == NULL )
    {
        return OUT_OF_MEMORY ;
    }
    if ( (pctrl = (struct buf_ctrl *)TL_malloc( (16+1)*12 )) == NULL )
    {
		error = OUT_OF_MEMORY ;
        goto FILEFIN_1 ;
    }
*/

// シェル対応のプログラムの場合ワークは,auto変数 or static変数を
// 使わないとWAV関数とうまくいかないこともある.何故かはわからない
	char buffer[ (16+1)*4096 + (16+1)*12 + 1024 ] ;
	pring = buffer ;
	pctrl = (struct buf_ctrl *)( buffer + (16+1)*4096 +512 );

    //  リングバッファ管理テーブルの作成
    pctrl->sum = 16 ;                       //  バッファ総数の設定
    pctrl->apply_loc = 0 ;                  //  アプリケーション位置のクリア
    WAV_makeTable( pring, (char *)pctrl ) ;
    //  サンプリングデータを保存するファイルを作成する
    if ( (pFile = fopen( sndFileName, "wb" )) == NULL )  //  ファイル作成
    {
		error = CANT_SAVE ;
        goto FILEFIN_2 ;
    }
    //  WAVEファイルの情報を作成しファイルに書きだす
    WAV_setWaveInfo_2( head, recordingFreq, recordingBitN, recordingKind, recordingPcmSize, &pcmstart ) ;
    if ( (wrtsize = fwrite( head, 1, 44, pFile)) != 44 )
    {
		error = CANT_SAVE ;
        goto FILEFIN_3 ;
    }
    //  録音前準備
    remain = recordingPcmSize ;                //  残りサンプリングデータサイズ設定
    rec_n_count = 0 ;                     //  カウンタ値のクリア
    nextloc = 4 ;                     //  次回のアプリケーション位置の設定
    wrtsz = 4*4096 ;                  //  一回当たりのファイル書き込みサイズ
	total = 0 ;
    WAV_recPrepare( recordingFreq, recordingBitN, recordingKind, NULL, recSyncfunc ) ;

//	setMsgColor( recMesId[0], EXE_COLOR ) ;		// 実行の表示色を変える

    //  録音開始
    WAV_rec( WAV_REC_IMMEDIATE, 0, recordingPcmSize ) ;      //  録音を行う

    //  指定サイズ録音されるまで繰り返す
    while( fl == 0 )
    {
		playing_hook() ;
        if( recMode == -1 )
        {
			WAV_recStop() ;
            goto FILEFIN_4 ;
        }

        WAV_getStatus( &status ) ;
        if ( !( status & WAV_ST_REC_PROCESS ) )   //  録音処理が終了していれば
            fl++ ;                                  //  flに1設定

    //  リングバッファ４個分サンプリングされていればファイルにデータを書きだす
        if ( rec_n_count >= 4 )
        {
            rec_n_count -= 4 ;                          //  カウンタ値の再設定
                                                    //  書き込むサイズの設定
            if ( remain < wrtsz ) wrtsz = remain ;
                                                    //  ファイルに書きだす
            if ( (wrtsize = fwrite( pctrl->buftbl[pctrl->apply_loc].ptr,
                                      1, wrtsz, pFile)) != wrtsz )
            {
				WAV_recStop( ) ;	// 強制終了
				error = CANT_SAVE ;
                goto FILEFIN_4 ;
            }
            else
            {
            	total += wrtsize ;
            }
   //  次回のアプリケーション位置を設定し、次々回のアプリケーション位置を算出
            pctrl->apply_loc = nextloc ;
            if ( (nextloc += 4) == pctrl->sum )  nextloc = 0 ;

            //  サンプリングデータの残りサイズの算出
            remain -= wrtsize ;
        }
   //  録音処理が終了していれば、残りのデータを全てファイルに書きだす
        else if ( ( fl != 0 ) && ( remain > 0 ) )
        {
//			setMsgColor( recMesId[0], MOJI_COLOR ) ;	// 実行の表示色を変える

            if ( (wrtsize = fwrite( pctrl->buftbl[pctrl->apply_loc].ptr,
                                        1, remain, pFile)) != remain )
            {
				WAV_recStop( ) ;	// 強制終了
				error = CANT_SAVE ;
                goto FILEFIN_4 ;
            }
            else
            {
            	total += wrtsize ;
            }
        }
    } ;                                            //  while文の終了

  FILEFIN_4 :;
	if( fseek( pFile, 0, SEEK_SET ) )total -= 4*4096 ;	// 16k失うかも
	if( total < 0 )total = 0 ;
    WAV_setWaveInfo_2( head, recordingFreq, recordingBitN, recordingKind, total, &pcmstart ) ;
    if ( (wrtsize = fwrite( head, 1, 44, pFile)) != 44 )
    {
        error = CANT_SAVE ;
        goto FILEFIN_3 ;
    }

      //  後処理
  FILEFIN_3 :;
    fclose( pFile ) ;
    if( total == 0 ) remove( sndFileName ) ;
  FILEFIN_2 :;
//    TL_free( pctrl ) ;
  FILEFIN_1 :;
//    TL_free( pring ) ;

//	setMsgColor( recMesId[0], MOJI_COLOR ) ;	// 実行の表示色を変える

	recMode = 0 ;

    return error ;
}

//  メモリ上へのサンプリング
static int recmemory()
{
    FILE  *pFile ;                //  ファイルポインタ
    char  *pring ;                //  リングバッファポインタ
    struct  buf_ctrl
    {
        int   sum ;
        int   apply_loc ;
        int   system_loc ;
        struct
        {
            char  *ptr ;
            char  reserve[8] ;
        }   buftbl[2] ;
    }   *pctrl ;                 //  リングバッファ管理テーブルポインタ
    char  *pdata ;                //  サンプリングデータ格納領域ポインタ
    int   pcmstart ;              //  PCMデータ相対開始位置
    int   error ;

	error = NOERR ;

    //  リングバッファとリングバッファ管理テーブルの領域の確保を行う
    //  リングバッファ数は２個
/*
    if ( (pring = TL_malloc( (2+1)*4096 )) == NULL )
    {
        return OUT_OF_MEMORY ;
    }
    if ( (pctrl = (struct buf_ctrl *)TL_malloc( (2+1)*12 )) == NULL )
    {
		error = OUT_OF_MEMORY ;
        goto MEMFIN_1 ;
    }
*/

// シェル対応のプログラムの場合ワークは,auto変数 or static変数を
// 使わないとWAV関数とうまくいかないこともある.何故かはわからない
	char buffer[ (2+1)*4096 + (2+1)*12 + 1024 ] ;
	pring = buffer ;
	pctrl = (struct buf_ctrl *)( buffer + (2+1)*4096 +512 );

    //  リングバッファ管理テーブルの作成
    pctrl->sum = 2 ;                           //  バッファ総数の設定
    pctrl->apply_loc = 0 ;                     //  アプリケーション位置のクリア
    WAV_makeTable( pring, (char *)pctrl ) ;

    //  サンプリングデータを格納する領域の確保
    if ( (pdata = TL_malloc( recordingPcmSize )) == NULL )
    {
		error = OUT_OF_MEMORY ;
        goto MEMFIN_2 ;
    }

    //  録音前準備
    WAV_recPrepare( recordingFreq, recordingBitN, recordingKind, pdata, (void (*)())NULL ) ;

    //  録音開始
	MG_mosDisp( 0 ) ;

//	setMsgColor( recMesId[0], EXE_COLOR ) ;		// 実行の表示色を変える

    SND_fm_timer_b_set( 0, 0 ) ;          //  音質向上の為タイマＢを停止
    WAV_rec( WAV_REC_COMPLETE, 0, recordingPcmSize ) ;
    SND_fm_timer_b_start() ;              //  タイマＢを再起動

//	setMsgColor( recMesId[0], MOJI_COLOR ) ;	// 実行の表示色を変える

	MG_mosDisp( 1 ) ;

    //  サンプリングデータをファイルに保存する
    if ( (pFile = fopen( sndFileName, "wb" )) == NULL )  //  ファイル作成
    {
        error = CANT_SAVE ;
        goto MEMFIN_3 ;
    }
    //  WAVEファイルの情報作成しファイルに書きだす
    //  （リングバッファ領域を作業領域として使用する）
    WAV_setWaveInfo_2( pring, recordingFreq, recordingBitN, recordingKind, recordingPcmSize, &pcmstart ) ;
    if( fwrite( pring, 1, 44, pFile) != 44 )
    {
        error = CANT_SAVE ;
        goto MEMFIN_4 ;
    }
    //  サンプリングしたデータをファイルに書きだす
    if( fwrite( pdata, 1, recordingPcmSize, pFile) != recordingPcmSize )
    {
        error = CANT_SAVE ;
        goto MEMFIN_4 ;
    }

    //  後処理
MEMFIN_4:;
    fclose( pFile ) ;
	if( error )remove( sndFileName ) ;
MEMFIN_3:;
    TL_free( pdata ) ;
MEMFIN_2:;
//    TL_free( pctrl ) ;
MEMFIN_1:;
//    TL_free( pring ) ;

    return error ;
}



/* 再生 */

static int playingMode = 0 ;	// -1ストップ 1再生 2早送り 0ﾃﾞﾌｫﾙﾄ
static int playOffset = 0 ;
static int playOffsetMax ;

/*	initDataIRCREC:recPlayBtnId:MJ_DBUTTONL40の呼び出し関数	*/
/*	initDataIRCREC:recStopBtnId:MJ_DBUTTONL40の呼び出し関数	*/
int	recPlay(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int alertobj ;
	int ret ;

	if( playingMode == 0 )
	{
		if( kobj == recPlayBtnId )
		{
			alertobj = MMI_GetAlertObj() ;  /*  現在のALERTOBJを退避  　  */
			MMI_SetAlertObj( recSubDialogId2 ) ;

			playingMode = 1 ;
			playOffset = 0 ;
PLAY00:
			setMsgColor( recMesId[1], EXE_COLOR ) ;
			ret = sndPlay() ;
			setMsgColor( recMesId[1], MOJI_COLOR ) ;
			if( ret )
			{
				if( ret < 0 )
				{
					errorCheck2( "規格外のサンプリングレートです｡" ) ;
				}
				else
				{
					errorCheck( ret ) ;
				}
			}
			else
			{
				if( playingMode == 2 )
				{
					playingMode = 1 ;
					goto PLAY00 ;
				}
			}

			playingMode = 0 ;
//			MMI_FlushEvnt() ;

			MMI_SetAlertObj( alertobj ) ;  /*  ALERTOBJを元に戻す    　   */

		}
	}
	else
	{
		if( kobj == recStopBtnId )
		{
			playingMode = -1 ;
		}
	}

	return NOERR ;
}

/*	initDataIRCREC:recPlayBarId:MJ_SCRLL40の呼び出し関数	*/
int	recPlayBarSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int	var, min, max, len, page ;			/* スクロールの変数 */

	if( playingMode != 0 )
	{
		MMI_SendMessage( recPlayBarId, MM_GETSCROLL, 5,
							&var, &min, &max, &len, &page ) ;

		playOffset = var ;
		playingMode = 2 ;
	}

	return NOERR ;
}

sndPlay()
{
	int ret ;

    WAV_setVolume( 127, 127 ) ;                       //  再生音量の設定
	ret = playfile() ;

	return ret ;
}

static int n_count ;
static int now_count ;

//  同期関数
//  注意：この同期関数のアドレスが０の場合、NULL指定と誤判断されるので、
//        この関数の位置には注意が必要
void  syncfunc()
{
    n_count ++ ;
    now_count ++ ;
    return ;
}

// 直接ファイルから再生
// 規格外のサンプリングレートならマイナスの値を返す
int  playfile()
{
    FILE  *pFile ;                      //  ファイルポインタ
    char  *pring ;                      //  リングバッファポインタ
    struct    buf_ctrl
    {
        int   sum ;
        int   apply_loc ;
        int   system_loc ;
        struct
        {
            char  *ptr ;
            char  reserve[8] ;
        }   buftbl[2] ;
    }   *pctrl ;                       //  リングバッファ管理テーブルポインタ
    int   ret ;                         //  戻り値
    int   ch, x, y ;                    //  マウス用変数
    int   remain ;                      //  残りサンプリングデータサイズ
    int   fl = 0 ;                      //  無限ループフラグ
    int   status ;                      //  ステータス
    int   nextloc ;                     //  次回のアプリケーション位置
    int   freq ;                        //  サンプリング周波数
    int   bitno ;                       //  サンプリングビット数
    int   kind ;                        //  データ種別
    int   pcmsz ;                       //  PCMデータサイズ
    int   pcmstart ;                    //  PCMデータ相対開始位置
    int   rdsz ;                        //  読み込むデータサイズ
    int   rdsize ;                      //  読み込まれたデータサイズ
    int   error ;

	error = NOERR ;

    //  リングバッファとリングバッファ管理テーブルの領域の確保を行う
    //  リングバッファ数は16個
/*
    if ( (pring = TL_malloc( (16+1)*4096 )) == NULL )
    {
        return OUT_OF_MEMORY ;
    }
    if ( (pctrl = (struct buf_ctrl *)TL_malloc( (16+1)*12 )) == NULL )
    {
        error = OUT_OF_MEMORY ;
		playingMode = 0 ;
        goto FILEFIN_1 ;
    }
*/
/*
	int lot ;

	lot = TL_getLot() ;
	if( (pring = (char *)TL_mallocMemory( lot, (16+1)*4096 + (16+1)*12 ))
																 == NULL )
    {
		if( lot )
			TL_freeLot( lot ) ;
        return OUT_OF_MEMORY ;
    }
    pctrl = (struct buf_ctrl *)( pring +  (16+1)*4096 ) ;
*/

// シェル対応のプログラムの場合ワークは,auto変数 or static変数を
// 使わないとWAV関数とうまくいかないこともある.何故かはわからない
	char buffer[ (16+1)*4096 + (16+1)*12 + 1024 ] ;
	pring = buffer ;
	pctrl = (struct buf_ctrl *)( buffer + (16+1)*4096 +512 );

    //  リングバッファ管理テーブルの作成
    pctrl->sum = 16 ;                        //  バッファ総数の設定
    pctrl->apply_loc = 0 ;                   //  アプリケーション位置のクリア
    WAV_makeTable( pring, (char *)pctrl ) ;

    //  再生ファイルをオープンする
    if ( (pFile = fopen( sndFileName, "rb" )) == NULL )  //  ファイルオープン
    {
        error = CANT_LOAD ;
		playingMode = 0 ;
        goto FILEFIN_2 ;
    }

    //  リングバッファを使用してファイルの情報を取得する
    rdsz = 0 ;
    do
    {
        rdsz += 50 ;
        //  ファイルポインタをWAVEデータの先頭に位置づける
        ret = fseek( pFile, 0, SEEK_SET ) ;
        if ( ret != 0 )
        {
	        error = CANT_LOAD ;
			playingMode = 0 ;
            goto FILEFIN_3 ;
        }
        rdsize = fread( pring, 1, rdsz, pFile ) ;

        if ( rdsize != rdsz )
        {
	        error = CANT_LOAD ;
			playingMode = 0 ;
            goto FILEFIN_3 ;
        }
        ret = WAV_getWaveInfo( pring, rdsz, &freq, &bitno, &kind,
                                                     &pcmsz, &pcmstart) ;
	} while( ret == 23 ) ;

	if( ret == 23 )
    {
        error = ILLIGAL_DATA ;
		playingMode = 0 ;
        goto FILEFIN_3 ;
    }

	int	var, min, max, len, page ;			/* スクロールの変数 */
	int firstPcmsz ;

	playOffsetMax = pcmsz / 4096 ;

	MMI_SendMessage( recPlayBarId, MM_GETSCROLL, 5,
						&var, &min, &max, &len, &page ) ;
	MMI_SendMessage( recPlayBarId, MM_SETSCROLL, 5,
						playOffset, min, playOffsetMax, len, page ) ;
	MMI_SendMessage( recPlayBarId, MM_SHOW, 0 ) ;

	if( (freq != 44100) && (freq != 22050) && (freq != 11025) )
	{
        error = -ILLIGAL_DATA ;		// 規格外のサンプリングレート
		playingMode = 0 ;
        goto FILEFIN_3 ;
    }

    //  ファイルポインタをPCMデータの先頭に位置づける
    ret = fseek( pFile, pcmstart + playOffset*4096, SEEK_SET ) ;
    if ( ret != 0 )
    {
        error = CANT_LOAD ;
		playingMode = 0 ;
        goto FILEFIN_3 ;
    }
	firstPcmsz = playOffset*4096 ;
    pcmsz -= ( playOffset*4096 ) ;

    //  再生データをリングバッファ分先読みしておく
    rdsz = 16*4096 ;
    if ( rdsz > pcmsz )  rdsz = pcmsz ;
    if ( (rdsize = fread( pctrl->buftbl[pctrl->apply_loc].ptr,
                                1, rdsz, pFile )) != rdsz )
    {
        error = CANT_LOAD ;
		playingMode = 0 ;
        goto FILEFIN_3 ;
    }

    //  再生前準備
    remain = pcmsz - rdsize ;	//  残りPCMデータサイズ設定
    n_count = 0 ;				//  カウンタ値のクリア

    now_count = 0 ;				//  カウンタ値のクリア

    nextloc = 4 ;				//  次回のアプリケーション位置の設定
    rdsz = 4*4096 ;				//  一回当たりのファイル読み込みサイズ
    WAV_playPrepare( freq, bitno, kind, NULL, syncfunc ) ;

    //  再生開始
    WAV_play( pcmsz ) ;                               //  再生を行う

    //  指定サイズ再生されるまで繰り返す
    while( fl == 0 )
    {
		playing_hook() ;
        if( playingMode != 1 )
			WAV_playStop() ;

        WAV_getStatus( &status ) ;
        if ( !( status & WAV_ST_PLAY_PROCESS ) )   //  再生処理が終了していれば
            fl++ ;                                 //  flに1設定

        //  リングバッファ４個分再生されていればファイルからデータを読みだす
        if ( ( remain > 0 ) && ( n_count >= 4 ) )
        {
            n_count -= 4 ;                            //  カウンタ値の再設定
                                                      //  読みだすサイズの設定
            if ( remain < rdsz ) rdsz = remain ;
                                                      //  ファイルから読みだす
            if ( (rdsize = fread( pctrl->buftbl[pctrl->apply_loc].ptr,
                                    1, rdsz, pFile )) != rdsz )
            {
				WAV_playStop() ;
			    error = CANT_LOAD ;
				playingMode = 0 ;
                goto FILEFIN_3 ;
            }

   //  次回のアプリケーション位置を設定し、次々回のアプリケーション位置を算出
            pctrl->apply_loc = nextloc ;
            if ( (nextloc += 4) == pctrl->sum )    nextloc = 0 ;

            //  サンプリングデータの残りサイズの算出
            remain -= rdsize ;

        }

		if( playingMode == 1 )
		{
			int point ;
			point = (firstPcmsz+now_count*4096)/4096 ;
			if( point > playOffsetMax )point = playOffsetMax ;
			MMI_SendMessage( recPlayBarId, MM_SETSCROLL, 5,
								point, min, playOffsetMax, len, page ) ;
			MMI_SendMessage( recPlayBarId, MM_SHOW, 0 ) ;
		}
    } ;                                              //  while文の終了

    //  後処理
FILEFIN_3 :;
    fclose( pFile ) ;
FILEFIN_2 :;
//	TL_free( pctrl ) ;
FILEFIN_1 :;
//	TL_free( pring ) ;
//	TL_freeLot( lot ) ;

	if( playingMode == -1 || playingMode == 1 )
		playingMode = 0 ;

    return error ;
}

/*	メインループ中のフック用関数	*/
static int	playing_hook( void )
{
	EVENT	*pev ;

	MMI_iosense() ;

	/*	全イベントを検出する	*/
	if( MMI_GetEvnt( EVALL, &pev ) == NOERR )
	{
		MMI_ExecEvnt( pev ) ;					/*	イベント実行	*/
	}
	return	0 ;
}










/* 情報 */

int	information(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	/* メニューとボタンを使えないようにする */
	MTL_setAtrObj( menubarId, MS_DSPONLYL40 ) ;
	MTL_setAtrObj( SDKmItemId[2], MS_INACTIVEL40 ) ;

	sndInf() ;

	/* メニューとボタンを使えるように戻す */
	MTL_resetAtrObj( menubarId, (~MS_DSPONLYL40) ) ;
	MTL_resetAtrObj( SDKmItemId[2], (~MS_INACTIVEL40) ) ;

	return NOERR ;
}



/*

		ここからは 汎用サブルーチン

*/

/* name , kakuchou[拡張子(.***)] → fullname = name + kakuchou */

file_kakuchousi_set( char *fullname, char *name, char *kakuchou )
{
	int i;

	for( i=0 ; i<76 ; i++ ){
		fullname[i] = name[i];
		if( name[i] == '.' || name[i] == (char)0 )goto mov01;
	}
	return 55;		/* bad file name */
mov01:	if( i == 0 )return 55;
	if( name[i-1] == '\\' )return 55;
	DWORD( fullname + i ) = DWORD( kakuchou );
	fullname[i+4] = (char)0;
	return 0;
}

/* return DWORD( ".拡張子" ) */

int get_file_kakucho( char *name )
{
	int i, j, f ;
	char kaku[4] ;

	for( i=0 ; i<4 ; i++ )kaku[i] = (char)0;
	f = 0 ;
	for( j=0 ; j<80 ; j++ ){
		if( name[j] == '.' )f = 1 ;
		if( name[j] == '\0' )break ;
	}
	if( f == 0 )return 0;		/* 拡張子なし */
	if( j > 79 )j = 79 ;
	for( i=j ; i>0 ; i-- )	/* 日本語の混乱を避けるため終わりからスキャン */
	{
		if( name[i] == '.' )goto mov01;
	}
	return 0;		/* 拡張子なし */
mov01:	if( i == 0 )return 0;
	for( j=0 ; j<4 ; j++ ){
		if( name[i] == '\0' )break ;
		kaku[j] = name[i];
		i++;
		if( (int)kaku[j] >= 0x61 && (int)kaku[j] <= 0x7a )
		    kaku[j] = (char)( (int)kaku[j] & 0xdf ); /* 大文字化 */
	}
	return DWORD( kaku );
}

/*	ファイル選択	*/

int	fileSelecter( path, ExtStr, title, exec, cncl )
char	*path ;
char	**ExtStr ;
char	*title ;
char	*exec ;
char	*cncl ;
{
	char pathName[100], name[20] ;
	int				 i, j, n ;
	unsigned int	MSlctCnt ;
	int		  Atr, ret, ret2 ;
	int alertobj ;  /*  ALERTOBJ退避  */

	ret2 = NOERR ;

	n = 0 ;
	for( i=0 ; i<79 ; i++ )
	{
		pathName[i] = path[i] ;
		if( path[i] == '\\' )
			n++ ;
		if( path[i] == '\0' )
			break ;
	}
	if( n <= 1 )
	{
		for( i=i ; i>=0 ; i-- )
		{
			if( path[i] == '\\' )
			{
				i++ ;
				pathName[i] = '\0' ;
				break ;
			}
		}
		for( j=0 ; j<13 ; j++ )
		{
			name[j] = path[i+j] ;
		}
	}
	else
	{
		for( i=i ; i>=0 ; i-- )
		{
			if( path[i] == '\\' )
			{
				pathName[i] = '\0' ;
				break ;
			}
		}
		for( j=0 ; j<13 ; j++ )
		{
			name[j] = path[i+1+j] ;
		}
	}

	ret = FDG_SetFileText( name ) ;
	ret = FDG_SetTitle( title, exec, cncl ) ;

	alertobj = MMI_GetAlertObj() ;  /*  現在のALERTOBJを退避  　  */
	MMI_SetAlertObj( FDG_GetMainID() ) ;

	ret = FDG_DspFileDlg(MMI_GetBaseObj(), FDG_FILEONLY | FDG_TEXT,
		 pathName, ExtStr,	&MSlctCnt) ;
	if( ret < 0 )	/* PATHが間違ってる場合はカレントディレクトリで */
	{
		name[0] = '\0' ;
		ret = FDG_SetFileText( name ) ;
		ret = FDG_DspFileDlg(MMI_GetBaseObj(), FDG_FILEONLY | FDG_TEXT,
			 NULL, ExtStr,	&MSlctCnt) ;
	}

	MMI_SetAlertObj( alertobj ) ;  /*  ALERTOBJを元に戻す    　   */

	if( (ret == 1) && (MSlctCnt > 0) )	/*	正しくファイル名を収得したか？	*/
	{
		FDG_GetPathName( path, &Atr, 0 ) ;
	}
	else
	{
		ret2 = 1 ;
	}
	ret = FDG_RecovCurDir() ;
	return ret2 ;
}


/*	パレット設定 */

int	setPalette( char *ework )
{
	char	para[16*8+4] ;
	int		ptr, colnum ;

	void 	set1Pal( int col, int b, int r, int g )
	{
		DWORD(para + ptr) = col ;
		BYTE(para + ptr + 4) = b * 16 ;
		BYTE(para + ptr + 5) = r * 16 ;
		BYTE(para + ptr + 6) = g * 16 ;
		BYTE(para + ptr + 7) = 0 ;
		ptr += 8 ;
	}

//	EGB_getTmenuPalette( para ) ;
//	colnum = DWORD(para) ;

	colnum = 0 ;		/* 強制的に色設定にしてしまう 1993 12 */

	if( colnum == 6 )	ptr = 52 ;
	else				ptr = 4 ;
	if( colnum != 16 )
	{
		set1Pal( 2, 4, 12, 6 ) ;
		set1Pal( 3, 5, 5, 5 ) ;		// 		set1Pal( 3, 10, 15, 12 ) ;
		set1Pal( 4, 9, 9, 9 ) ;
		set1Pal( 5, 7, 0, 12 ) ;
		set1Pal( 10, 0, 13, 0 ) ;
		set1Pal( 11, 10, 0, 0 ) ;
		set1Pal( 12, 0, 0, 15 ) ;
		set1Pal( 13, 15, 0, 15 ) ;
		set1Pal( 14, 0, 15, 13 ) ;
		if( colnum != 6 )
		{		/* メニュー色(green系) */
			set1Pal( 1, 4, 4, 8 ) ;
			set1Pal( 6, 12, 12, 12 ) ;
			set1Pal( 7, 7, 7, 7 ) ;
			set1Pal( 8, 2, 2, 2 ) ;
			set1Pal( 9, 8, 10, 12 ) ;	/* file selector */
			set1Pal( 15, 15, 15, 15 ) ;
		}
		DWORD(para + 0) = 15 ;
	}
	else
		DWORD(para + 0) = colnum ;
	EGB_palette( ework, 1, para ) ;

	return NOERR ;
}

/* 準備 */

int startSet()
{
	extern int recTimeNumId ;

	int timeMax ;
	int var, min, max, delta, ptColumn ;
	int len, page, i ;

	/* GUI EDITORの不備のため設定できない部分を設定 */

	/* rec */
	timeMax = 99999 ;

	MMI_SendMessage( recTimeNumId, MM_GETNUMBOX, 5, /* 録音時間 */
							&var, &min, &max, &delta, &ptColumn ) ;
	MMI_SendMessage( recTimeNumId, MM_SETNUMBOX, 5, /* 変更 */
							var, min, timeMax, delta, ptColumn ) ;

	/* ボリュームセット */
	SND_elevol_mute( 0x00000000 ) ;
	MMI_SendMessage( recLineNumId, MM_GETNUMBOX, 5, /* Line Volune set */
							&var, &min, &max, &delta, &ptColumn ) ;
	if( var )
		SND_elevol_set( 0, var, var ) ;

	MMI_SendMessage( recCdNumId, MM_GETNUMBOX, 5, /* CD Volune set */
							&var, &min, &max, &delta, &ptColumn ) ;
	if( var )
		SND_elevol_set( 1, var, var ) ;

	MMI_SendMessage( recMicNumId, MM_GETNUMBOX, 5, /* Mic Volune set */
							&var, &min, &max, &delta, &ptColumn ) ;
	if( var )
		SND_elevol_set( 2, var, var ) ;

	sndEffectFftStart() ;
	fileSet() ;

	return NOERR ;
}

/* スリープ時の設定 */
int sleepSet()
{
//	WAV_end() ;            //  WAVEライブラリの初期化
	sndFft_end() ;		// メモリ解放
	return NOERR ;
}

/* 起こされた時の設定 */
int wakeSet()
{
//	WAV_init() ;            //  WAVEライブラリの初期化
	return NOERR ;
}

/*	終了処理	*/
int	quitFunc()
{
	sndFft_end() ;		// メモリ解放
	MMI_SetHaltFlag( TRUE ) ;

	return NOERR ;
}

/*	終了可能なら終了する処理	*/
int	quitFunc2()
{
	if( MTL_checkAtrObj( menubarId, MS_DSPONLYL40 ) == 0 )
	{
		sndFft_end() ;		// メモリ解放
		MMI_SetHaltFlag( TRUE ) ;
		return NOERR ;
	}
	return ILLEGAL_FUNCTION ;
}

/*	あばうと表示	*/

int	aboutFunc()
{
	MMI_SendMessage( alertId, MM_ATTACH, 1, MMI_GetBaseObj() ) ;
	MMI_SendMessage( alertId, MM_SHOW, 0 ) ;

	MMI_ExecSystem() ;

	MMI_SendMessage( alertId, MM_ERASE, 0 ) ;
	MMI_SendMessage( alertId, MM_DETACH, 0 ) ;
	return NOERR ;
}

/*	あばうと表示確認	*/

int	aboutOKFunc(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	MMI_SetHaltFlag( TRUE ) ;

	return NOERR ;
}

/* 情報表示 */

sndInf()
{
	int var, min, max, delta, ptColumn ;

    int   freq = 0 ;                    //  サンプリング周波数
    int   bitno = 0 ;                   //  サンプリングビット数
    int   kind = 0 ;                    //  データ種別
    int   pcmsz = 0 ;                   //  PCMデータサイズ
    int   pcmstart ;                    //  PCMデータ相対開始位置
    int   time ;
    int   error ;

	error =
	readInfo( sndFileName, &freq, &bitno, &kind, &pcmsz, &pcmstart );

	if( error )
	{
		errorCheck( error ) ;
		return NOERR ;
	}

	MMI_SendMessage( infNumId[0], MM_GETNUMBOX, 5, /* freq */
							&var, &min, &max, &delta, &ptColumn ) ;
	MMI_SendMessage( infNumId[0], MM_SETNUMBOX, 5,
							freq, 0, freq, delta, ptColumn ) ;

	MMI_SendMessage( infNumId[1], MM_GETNUMBOX, 5, /* bit */
							&var, &min, &max, &delta, &ptColumn ) ;
	MMI_SendMessage( infNumId[1], MM_SETNUMBOX, 5,
							bitno, 0, bitno, delta, ptColumn ) ;

	MMI_SendMessage( infNumId[2], MM_GETNUMBOX, 5, /* ch 数 */
							&var, &min, &max, &delta, &ptColumn ) ;
	MMI_SendMessage( infNumId[2], MM_SETNUMBOX, 5,
							kind, 0, kind, delta, ptColumn ) ;

	MMI_SendMessage( infNumId[3], MM_GETNUMBOX, 5, /* size */
							&var, &min, &max, &delta, &ptColumn ) ;
	MMI_SendMessage( infNumId[3], MM_SETNUMBOX, 5,
							pcmsz, 0, pcmsz, delta, ptColumn ) ;

	if( (bitno * kind * freq ) != 0 )
		time = pcmsz*10/(bitno/8*kind)/freq ;
	else
		time = 0 ;
	MMI_SendMessage( infNumId[4], MM_GETNUMBOX, 5, /* time */
							&var, &min, &max, &delta, &ptColumn ) ;
	MMI_SendMessage( infNumId[4], MM_SETNUMBOX, 5,
							time, 0, time, delta, ptColumn ) ;

	MMI_SendMessage( infDialogId, MM_ATTACH, 1, MMI_GetBaseObj() ) ;
	MMI_SendMessage( infDialogId, MM_SHOW, 0 ) ;	/* 全体を見せる */

	MMI_ExecSystem() ;		/* Dialog表示へ･･･イベントループ */

	MMI_SendMessage( infDialogId, MM_ERASE, 0 ) ;
	MMI_SendMessage( infDialogId, MM_DETACH, 0 ) ;

	return NOERR ;
}

/* 情報確認 */

int	infOkFunc(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	MMI_SetHaltFlag( TRUE ) ;
	return NOERR ;
}

/* error 表示ルーチン */

static int errorCheckMode = 0 ;

int errorCheck( int number )
{
	/*
	#define	OUT_OF_MEMORY		7
	#define	ILLIGAL_FILENAME	55
	#define	ILLIGAL_DATA		58
	#define	CANT_LOAD			1
	#define	CANT_SAVE			2
	#define	NO_DATA				63
	*/

	errorCheckMode = 0 ;

	MMI_SendMessage( errormessage[0], MM_SETMSG, 1,
		 "エラーが発生しました｡" ) ;
	if( number == OUT_OF_MEMORY )
		MMI_SendMessage( errormessage[0], MM_SETMSG, 1,
		 "メモリが足りません。" ) ;
	if( number == ILLIGAL_FILENAME )
		MMI_SendMessage( errormessage[0], MM_SETMSG, 1,
		 "ファイル名が正しくありません｡" ) ;
	if( number == ILLIGAL_DATA )
		MMI_SendMessage( errormessage[0], MM_SETMSG, 1,
		 "データ形式が正しくありません｡" ) ;
	if( number == CANT_LOAD )
		MMI_SendMessage( errormessage[0], MM_SETMSG, 1,
		 "ロードできませんでした｡" ) ;
	if( number == CANT_SAVE )
		MMI_SendMessage( errormessage[0], MM_SETMSG, 1,
		 "セーブできませんでした｡" ) ;
	if( number == NO_DATA )
		MMI_SendMessage( errormessage[0], MM_SETMSG, 1,
		 "データが存在しません｡" ) ;

	MMI_SendMessage( errorId, MM_ATTACH, 1, MMI_GetBaseObj() ) ;
	MMI_SendMessage( errorId, MM_SHOW, 0 ) ;

	MMI_ExecSystem() ;		/* Dialog表示へ･･･イベントループ */
//  キー却下時onがある時にはこの方式はだめ
	MMI_SendMessage( errorId, MM_ERASE, 0 ) ;
	MMI_SendMessage( errorId, MM_DETACH, 0 ) ;

	return NOERR;
}

int errorCheck2( char *name )
{
	errorCheckMode = 1 ;

	MMI_SendMessage( errormessage[0], MM_SETMSG, 1, name ) ;

	MMI_SendMessage( errorId, MM_ATTACH, 1, MMI_GetBaseObj() ) ;
	MMI_SendMessage( errorId, MM_SHOW, 0 ) ;

	MMI_ExecSystem() ;		/* Dialog表示へ･･･イベントループ */

	MMI_SendMessage( errorId, MM_ERASE, 0 ) ;
	MMI_SendMessage( errorId, MM_DETACH, 0 ) ;

	return NOERR;
}

/*	エラー表示確認	*/

int	errorOKFunc(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{

	MMI_SetHaltFlag( TRUE ) ;

/*
	if( errorCheckMode == 0 )
	{
		MMI_SendMessage( errorId, MM_ERASE, 0 ) ;
		MMI_SendMessage( errorId, MM_DETACH, 0 ) ;
	}
	else
	{
		MMI_SetHaltFlag( TRUE ) ;

		MMI_SendMessage( errorId, MM_ERASE, 0 ) ;
		MMI_SendMessage( errorId, MM_DETACH, 0 ) ;
	}
*/

	return NOERR ;
}

/* メッセージのカラーを変えて表示する */

setMsgColor( int kobj, int color )
{
	OBJECT *pobj ;
	MSGL40 *data ;

	pobj = TL_getObjectPtr( kobj ) ;
	data = (MSGL40 *)(pobj->data) ;
	data->clr.ch = color ;
	MMI_SendMessage( kobj, MM_SHOW, 0 ) ;	/* 見せる */

	return NOERR ;
}

/* マウスボタンチェック */

mouseSwCheck()
{
	int sw ;

	SND_joy_in_1( 0x01, &sw );
	sw = ((sw ^ 0xff) & 0x30) >> 4 ;
	return sw ;
}

/* データの情報を得る */

static int readInfo( char *name, int *fq, int *bit, int *kd, int *sz, int *st )
{
    FILE  *pFile ;                      //  ファイルポインタ

	char head[512] ;

    int   ret ;                         //  戻り値
    int   freq = 0 ;                    //  サンプリング周波数
    int   bitno = 0 ;                   //  サンプリングビット数
    int   kind = 0 ;                    //  データ種別
    int   pcmsz = 0 ;                   //  PCMデータサイズ
    int   pcmstart = 44 ;               //  PCMデータ相対開始位置
    int   rdsz ;                        //  読み込むデータサイズ
    int   rdsize ;                      //  読み込まれたデータサイズ
    int   error ;

	error = NOERR ;

    //  再生ファイルをオープンする
    if ( (pFile = fopen( name, "rb" )) == NULL )  //  ファイルオープン
    {
        error = NO_DATA ;
        goto FILEFIN_2 ;
    }

    //  ファイルの情報を取得する
	for( rdsz = 50 ; rdsz <= 500 ; rdsz += 50 )
    {
        //  ファイルポインタをWAVEデータの先頭に位置づける
        ret = fseek( pFile, 0, SEEK_SET ) ;
        if ( ret != 0 )
        {
	        error = CANT_LOAD ;
            goto FILEFIN_3 ;
        }
        rdsize = fread( head, 1, rdsz, pFile ) ;

        if ( rdsize != rdsz )
        {
	        error = CANT_LOAD ;
            goto FILEFIN_3 ;
        }
        ret = WAV_getWaveInfo( head, rdsz, &freq, &bitno, &kind,
                                                     &pcmsz, &pcmstart) ;
		if( ret != 23 )
			break ;

	}

	if( ret == 23 )
    {
        error = ILLIGAL_DATA ;
        goto FILEFIN_3 ;
    }

    //  後処理
FILEFIN_3 :;
    fclose( pFile ) ;
FILEFIN_2 :;
FILEFIN_1 :;

	*fq = freq ;
	*bit = bitno ;
	*kd = kind ;
	*sz = pcmsz ;
	*st = pcmstart ;

	return error ;
}

typedef struct
{
		char riffld[4] ;
		int riffSize ;
		char formType[4] ;

		char fmtId[4] ;
		int fmtSize ;
		short int waveFormatType ;
		short int channel ;
		int samplesPerSec ;
		int bytesPerSec ;
		short int blockSize ;
		short int bitesPerSample ;

		char dataId[4] ;
		int dataSize ;

} WAVECHUNK ;

//int WAV_setWaveInfo( char *buf, int freq, int bitno, int kind,
//                     int pcmsz, int *pcmst ) ;
//  にバグあるため､代わりの関数

int WAV_setWaveInfo_2( char *buf,
					   int fq, int bit, int kd, int sz, int *pcmst )
{
	WAVECHUNK *wave ;

	wave = (WAVECHUNK *)buf ;

	DWORD( wave->riffld ) = DWORD( "RIFF" ) ;
	DWORD( wave->formType ) = DWORD( "WAVE" ) ;
	DWORD( wave->fmtId ) = DWORD( "fmt " ) ;
	DWORD( wave->dataId ) = DWORD( "data" ) ;
	wave->riffSize = sz + 36 ;
	wave->fmtSize = 16 ;
	wave->dataSize = sz ;

	wave->waveFormatType = 1 ;
	wave->channel = kd ;
	wave->samplesPerSec = fq ;
	wave->bytesPerSec = bit * kd / 8 * fq ;
	wave->blockSize = bit * kd / 8 ;
	wave->bitesPerSample = bit ;

	*pcmst = 44 ;

	return NOERR ;
}


/* fft */

static int fftChMode = 0 ;
static int fftSmpFreqMode = 1 ;
static int fftNMode = 0 ;
static int fftWinMode = 1 ;
static int fftMul = 1 ;
static int fftFreqMode = 1 ;

static int fftMode = 0 ; // 1:ループ -1:終了 0:デフォルト

int	sndEffectFftStart()
{
	int bit, kd, sz ;
	int var, min, max, delta, ptColumn ;
	int recCapacity ;

    WAV_getCapability( &recCapacity, 22050 ) ; 
    if ( recCapacity & WAV_CAP_16PCM_EXIST )
    {                              //  16ビットPCMによるサンプリング
		MTL_resetAtrObj( fftChBtnId[0], (~MS_DSPONLYL40) ) ;
		MTL_resetAtrObj( fftChBtnId[1], (~MS_DSPONLYL40) ) ;

		MTL_resetAtrObj( fftSmpFreqBtnId[0], (~MS_DSPONLYL40) ) ;
	}
    else
    {                             //  内蔵PCMによるサンプリング
		MTL_resetAtrObj( fftChBtnId[0], (~MS_DSPONLYL40) ) ;
		MTL_setAtrObj(   fftChBtnId[0], MS_INACTIVEL40 ) ;
		MTL_resetAtrObj( fftChBtnId[1], (~MS_DSPONLYL40) ) ;
		MTL_setAtrObj(   fftChBtnId[1], MS_INACTIVEL40 ) ;

		MTL_resetAtrObj( fftSmpFreqBtnId[0], (~MS_DSPONLYL40) ) ;
		MTL_setAtrObj( fftSmpFreqBtnId[0], MS_INACTIVEL40 ) ;
	}

	MTL_setFlagObj( fftChBtnId[fftChMode], (MS_UNSELECT | MS_TOGGLE) ) ;
	MTL_setFlagObj( fftNBtnId[fftNMode], (MS_UNSELECT | MS_TOGGLE) ) ;
	MTL_setFlagObj( fftSmpFreqBtnId[fftSmpFreqMode],
											 (MS_UNSELECT | MS_TOGGLE) ) ;
	MTL_setFlagObj( fftWinBtnId[fftWinMode], (MS_UNSELECT | MS_TOGGLE) ) ;
	MTL_setFlagObj( fftFreqBtnId[fftFreqMode], (MS_UNSELECT | MS_TOGGLE) ) ;

	MMI_SendMessage( fftSubDialogId, MM_ATTACH, 1, baseDialogId2 ) ;
	MMI_SendMessage( fftSubDialogId, MM_SHOW, 0 ) ;	/* 全体を見せる */

	return NOERR ;
}

int	sndEffectFftEnd()
{
	sndFft_end() ;		// メモリ解放

	MMI_SendMessage( fftSubDialogId, MM_ERASE, 0 ) ;
	MMI_SendMessage( fftSubDialogId, MM_DETACH, 0 ) ;

	return NOERR ;
}

/*	initDataIWVFFT:fftOkBtnId:MJ_DBUTTONL40の呼び出し関数	*/
int	fftOkchk(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int ret ;
	int alertobj ;

	if( fftMode == 0 )
	{
		alertobj = MMI_GetAlertObj() ;  /*  現在のALERTOBJを退避  　  */
		MMI_SetAlertObj( baseDialogId2 ) ;
		setMsgColor( fftMesId[0], EXE_COLOR ) ;

		fftMode = 1 ;
		while( fftMode == 1 )
		{
			int fq ;

			playing_hook() ;

			fq = ( 1 << (2 - fftSmpFreqMode) ) * 11025 ;

			ret = sndFft( fq, fftChMode, fftNMode+8, fftWinMode,
											 fftMul, fftFreqMode ) ;
			if( ret )break ;
		}
		fftMode = 0 ;

		setMsgColor( fftMesId[0], MOJI_COLOR ) ;
		MMI_SetAlertObj( alertobj ) ;  /*  ALERTOBJを元に戻す    　   */

		if( ret > 0 )
			errorCheck( ret ) ;
		else if( ret == -1 )
		{
			errorCheck2( "観測点がデータの外にでます｡" ) ;
		}
		else if( ret == -ILLIGAL_DATA )
		{
			errorCheck2( "規格外のサンプリングレートです｡" ) ;
		}

		MMI_FlushEvnt() ;	/* イベントをフラッシュ */
	}

	return NOERR ;
}

/*	initDataIWVFFT:fftCanBtnId:MJ_DBUTTONL40の呼び出し関数	*/
int	fftCanchk(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	if( fftMode == 1 )
	{
		fftMode = -1 ;
	}

	return NOERR ;
}

/*	initDataIWVFFT:fftChBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftChBtnId[1]:MJ_TICONL40の呼び出し関数	*/
int	fftChSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<2 ; i++ )
	{
		if( kobj == fftChBtnId[i] )
		{
			MTL_setFlagObj( fftChBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( fftChBtnId[fftChMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( fftChBtnId[fftChMode], MM_SHOW, 0 ) ;
			fftChMode = i ;
		}
	}
	return NOERR ;
}

/*	initDataIRCDSK:fftSmpFreqBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIRCDSK:fftSmpFreqBtnId[1]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIRCDSK:fftSmpFreqBtnId[2]:MJ_TICONL40の呼び出し関数	*/
int	fftSmpFreqSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<3 ; i++ )
	{
		if( kobj == fftSmpFreqBtnId[i] )
		{
			MTL_setFlagObj( fftSmpFreqBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( fftSmpFreqBtnId[fftSmpFreqMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( fftSmpFreqBtnId[fftSmpFreqMode], MM_SHOW, 0 ) ;
			fftSmpFreqMode = i ;
		}
	}
	return NOERR ;
}

/*	initDataIWVFFT:fftNBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftNBtnId[1]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftNBtnId[2]:MJ_TICONL40の呼び出し関数	*/
int	fftNSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<3 ; i++ )
	{
		if( kobj == fftNBtnId[i] )
		{
			MTL_setFlagObj( fftNBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( fftNBtnId[fftNMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( fftNBtnId[fftNMode], MM_SHOW, 0 ) ;
			fftNMode = i ;
		}
	}
	return NOERR ;
}

/*	initDataIWVFFT:fftWinBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftWinBtnId[1]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftWinBtnId[2]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftWinBtnId[3]:MJ_TICONL40の呼び出し関数	*/
int	fftWinSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<4 ; i++ )
	{
		if( kobj == fftWinBtnId[i] )
		{
			MTL_setFlagObj( fftWinBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( fftWinBtnId[fftWinMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( fftWinBtnId[fftWinMode], MM_SHOW, 0 ) ;
			fftWinMode = i ;
		}
	}
	return NOERR ;
}

/*	initDataIWVFFT:fftMulScrId:MJ_SCRLL40の呼び出し関数	*/
int	fftMulSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int var, min, max, len, page ;
	int var2, min2, max2, delta2, ptColumn2 ;

	MMI_SendMessage( kobj, MM_GETSCROLL, 5,
										&var, &min, &max, &len, &page ) ;

	fftMul = 1 << var ;

	MMI_SendMessage( fftMulNumId, MM_GETNUMBOX, 5,
							&var2, &min2, &max2, &delta2, &ptColumn2 ) ;
	MMI_SendMessage( fftMulNumId, MM_SETNUMBOX, 5,
							fftMul, min2, max2, delta2, ptColumn2 ) ;
	MMI_SendMessage( fftMulNumId, MM_SHOW, 0 ) ;

	sndFftWave( fftMul ) ;

	return NOERR ;
}

/*	initDataIWVFFT:fftFreqBtnId[0]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftFreqBtnId[1]:MJ_TICONL40の呼び出し関数	*/
/*	initDataIWVFFT:fftFreqBtnId[2]:MJ_TICONL40の呼び出し関数	*/
int	fftFreqSet(kobj, messId, argc, pev, trigger)
int		kobj ;
int		messId ;
int		argc ;
EVENT	*pev ;
int		trigger ;
{
	int i ;

	for( i=0 ; i<3 ; i++ )
	{
		if( kobj == fftFreqBtnId[i] )
		{
			MTL_setFlagObj( fftFreqBtnId[i], MS_UNSELECT ) ;
			MTL_resetFlagObj( fftFreqBtnId[fftFreqMode],
								 (~(MS_UNSELECT | MS_TOGGLE)) ) ;
			MMI_SendMessage( fftFreqBtnId[fftFreqMode], MM_SHOW, 0 ) ;
			fftFreqMode = i ;
		}
	}

	sndFftSpecDsp( fftFreqMode ) ;

	return NOERR ;
}


// ワーク & バッファ
static char *fftBuffer ;
static double *fftReal, *fftImag ;
static double *fftWin ;
static char *fftWork ;
static int *fftData ;

static int sndFftDataFlg = 0 ;	/* 1:ワーク&データ確保 0:なにもない状態 */
static int sndFftFreq ;			/* サンプリングレート */
static int sndFftEx ;			/* 2のNじょう */

static int sndFft( int smpfreq, int chMode, int ex, int winMode,
												 int mul, int dspMode )
{
	int i ;
	int x1, x2, ret ;
	int fq, bit, kd, sz ;
	int sndLength ;
	int length, size ;
	int recCapacity ;

	sndFftEx = ex ;
	length = 1 << ex ;

	// ワークエリアの確保
	if( sndFftDataFlg )
		TL_free( fftBuffer ) ;
	sndFftDataFlg = 0 ;

	size = length*sizeof( double )* 3 + sizeof( double )*length*3
	     + length*sizeof( int ) ;

	if( (fftBuffer = (char *)TL_malloc( size )) == NULL )
		return OUT_OF_MEMORY ;

	if(TL_checkMemory(1) * 4096 < MinMem)	/*	必要とする動作メモリのcheck	*/
	{
		TL_free( fftBuffer ) ;
		return OUT_OF_MEMORY ;
	}

	fftReal = (double *)fftBuffer ;
	fftImag = fftReal + length ;
	fftWin  = fftImag + length ;
	fftWork = (char *)(fftWin + length) ;
	fftData = (int *)( fftWork + sizeof( double )*length*3 ) ;

	sndFftFreq = smpfreq ;

    WAV_getCapability( &recCapacity, 22050 ) ; 
    if ( recCapacity & WAV_CAP_16PCM_EXIST )
    {                              //  16ビットPCMによるサンプリング
		fftRecMemory( smpfreq, length, chMode ) ;
	}
	else
	{
		fftRecMemory2( smpfreq, length ) ;
	}

	sndFftDataFlg = 1 ;

//	sndFftWave( mul ) ;
	sndFftSpec( winMode ) ;
	sndFftWave( mul ) ;
	sndFftSpecDsp( dspMode ) ;

	return NOERR ;
}

static int sndFft_end()
{
	if( sndFftDataFlg )
		TL_free( fftBuffer ) ;
	sndFftDataFlg = 0 ;
	return NOERR ;
}

static int sndFftWave( int mul )
{
	extern char	*guiEgbPtr ;			/*	EGB のワークアドレス	*/

	HYPER hyp ;
	int x0, y0 ;
	int length ;
	int i, d ;
	static char *dsp[] = {
								"0      8      16msec.",
								"0      4      8msec.",
								"0      2      4msec.",
								"0      1      2msec.",
								"0     0.5     1msec."
							} ;
	char para[ 2 + 4*512 ] ;

	if( sndFftDataFlg == 0 )
		return NOERR ;

	length = 1 << sndFftEx ;

	MMI_SendMessage( fftWaveBaseMesId, MM_GETHYPER, 1, &hyp ) ;
	x0 = hyp.fr.lupx ;
	y0 = hyp.fr.lupy ;

	switch( sndFftEx )
	{
	case 8:	WORD( para ) = 256 ;
			for( i=0 ; i<256 ; i++ )
			{
				WORD( para + 2 + 4*i ) = x0 + i*2 ;
				d = - fftData[i]*50*mul / 32768 ;
				if( d < -50 )d = -50 ;
				if( d >  50 )d =  50 ;
				WORD( para + 2 + 4*i + 2 ) = y0 - d ;
			}
			break ;
	case 9:	WORD( para ) = 512 ;
			for( i=0 ; i<512 ; i++ )
			{
				WORD( para + 2 + 4*i ) = x0 + i ;
				d = - fftData[i]*50*mul / 32768 ;
				if( d < -50 )d = -50 ;
				if( d >  50 )d =  50 ;
				WORD( para + 2 + 4*i + 2 ) = y0 - d ;
			}
			break ;
	case 10: WORD( para ) = 512 ;
			for( i=0 ; i<512 ; i++ )
			{
				WORD( para + 2 + 4*i ) = x0 + i ;
				d = - fftData[i*2]*50*mul / 32768 ;
				if( d < -50 )d = -50 ;
				if( d >  50 )d =  50 ;
				WORD( para + 2 + 4*i + 2 ) = y0 - d ;
			}
			break ;
	}

//	switch( sndFftFreq / 11025 * length / 256 )
	switch( sndFftFreq / 11025 * 1024 / length )
	{
	case 1 :
		MMI_SendMessage( fftScaleMesId, MM_SETMSG, 1, dsp[0] ) ;
		break ;
	case 2 :
		MMI_SendMessage( fftScaleMesId, MM_SETMSG, 1, dsp[1] ) ;
		break ;
	case 4 :
		MMI_SendMessage( fftScaleMesId, MM_SETMSG, 1, dsp[2] ) ;
		break ;
	case 8 :
		MMI_SendMessage( fftScaleMesId, MM_SETMSG, 1, dsp[3] ) ;
		break ;
	case 16 :
		MMI_SendMessage( fftScaleMesId, MM_SETMSG, 1, dsp[4] ) ;
		break ;
	}

	EGB_color(guiEgbPtr,0,15);
	EGB_paintMode(guiEgbPtr,0x222);
	EGB_writeMode(guiEgbPtr,0);

	MMI_SendMessage( fftMulScrId, MM_ERASE, 0 ) ;
	MMI_SendMessage( fftSubDialogId2, MM_SHOW, 0 ) ;
	MG_mosDisp( 0 ) ;
	EGB_connect(guiEgbPtr,para);
	MG_mosDisp( 1 ) ;

	return NOERR ;
}

static int sndFftSpec( int winMode )
{
	int i ;
	int length ;

	length = 1 << sndFftEx ;

	sndFftWin( winMode, length ) ;

	for( i=0 ; i<length ; i++ )
	{
		fftReal[i] = fftWin[i] * fftData[i] ;
		fftImag[i] = 0 ;
	}

	fft_1( fftWork, fftReal, fftImag, sndFftEx, 1 );

	return NOERR ;
}

static int sndFftWin( int mode, int n )
{
	int i ;

	switch( mode )
	{
	case 0:	for( i=0 ; i<n ; i++ )	// ハニング
			{
				fftWin[i] = .5 - .5 * cos( 2 * _PI * i / n ) ;
			}
			break ;

	case 1:	for( i=0 ; i<n ; i++ )	// ハミング
			{
				fftWin[i] = .54 - .46 * cos( 2 * _PI * i / n ) ;
			}
			break ;

	case 2:	for( i=0 ; i<n ; i++ )	// ブラックマン
			{
				fftWin[i] = .42 - .5 * cos( 2 * _PI * i / n )
							+ .08 * cos( 4 * _PI * i / n ) ;
			}
			break ;

	case 3:	for( i=0 ; i<n ; i++ )	// 方形窓
			{
				fftWin[i] = 1 ;
			}
			break ;
	}

	return NOERR ;
}

static int sndFftSpecDsp( int dspMode )
{
	extern char	*guiEgbPtr ;			/*	EGB のワークアドレス	*/

	HYPER hyp ;
	int x0, y0 ;
	int i, step, total, dspExp ;
	int length ;
	static char *dsp[][2] = {
								{ "10k", "20kHz" },
								{ "5k",  "10kHz" },
								{ "  ",  "5kHz"  }
							} ;
	int max, db[512] ;
	char para[ 2 + 4*512 ] ;

	if( sndFftDataFlg == 0 )
		return NOERR ;

	length = 1 << sndFftEx ;

	for( i=0 ; i<(length >> 1) ; i++ )
	{
		db[i] = log10(fftReal[i] * fftReal[i] + fftImag[i] * fftImag[i]) * 20;
	}		/* スケールの関係からdBの2倍の値を取る */

	max = db[0] ;
	for( i=0 ; i<(length >> 1) ; i++ )
	{
		if( db[i] > max )max = db[i] ;
	}

	MMI_SendMessage( fftSpecBaseMesId, MM_GETHYPER, 1, &hyp ) ;
	x0 = hyp.fr.lupx ;
	y0 = hyp.fr.lupy ;

	dspExp = 1 << dspMode ;
	step = sndFftFreq / 11025 * 128 ;
	step = step * dspExp ;
	total = (length >> 1) ;

	switch( sndFftFreq )
	{
	case 44100:
		total = total / dspExp ;
		break ;
	case 22050:
		if( dspExp >= 4 )
		{
			total = total / 2 ;
		}
		break ;
	case 11025:
		break ;
	}

	WORD( para ) = total ;
	for( i=0 ; i<total ; i++ )
	{
		WORD( para + 2 + 4*i ) = x0 + i * step / (length >> 1) ;
		db[i] = db[i] - max + 159 ;
		if( db[i] > 159 )db[i] = 159 ;
		if( db[i] < 0 )db[i] = 0 ;
		WORD( para + 2 + 4*i + 2 ) = y0 - db[i] ;
	}

	MMI_SendMessage( fftFreqMesId[0], MM_SETMSG, 1, dsp[dspMode][0] ) ;
	MMI_SendMessage( fftFreqMesId[1], MM_SETMSG, 1, dsp[dspMode][1] ) ;

	EGB_color(guiEgbPtr,0,15);
	EGB_paintMode(guiEgbPtr,0x222);
	EGB_writeMode(guiEgbPtr,0);

	MG_mosDisp( 0 ) ;
	MMI_SendMessage( fftSubDialogId3, MM_SHOW, 0 ) ;
	EGB_connect(guiEgbPtr,para);
	MG_mosDisp( 1 ) ;

	return NOERR ;
}



//  FFT解析のためのサンプリング
static int fftRecMemory( int freq, int length, int chMode )
{
	int kind = 2 ;              //  データ種別
	int bitN = 16 ;                      //  サンプリングビット数
	int pcmSize = 44100 * (16/8) * 10 ;  //  サンプリングデータ長
	int i ;

	pcmSize = length * (16/8) * 2 ;  //  サンプリングデータ長

    char  *pring ;                //  リングバッファポインタ
    struct  buf_ctrl
    {
        int   sum ;
        int   apply_loc ;
        int   system_loc ;
        struct
        {
            char  *ptr ;
            char  reserve[8] ;
        }   buftbl[2] ;
    }   *pctrl ;                 //  リングバッファ管理テーブルポインタ
    char  *pdata ;                //  サンプリングデータ格納領域ポインタ
    int   pcmstart ;              //  PCMデータ相対開始位置
    int   error ;

	error = NOERR ;

    //  リングバッファとリングバッファ管理テーブルの領域の確保を行う
    //  リングバッファ数は２個
// シェル対応のプログラムの場合ワークは,auto変数 or static変数を
// 使わないとWAV関数とうまくいかないこともある.何故かはわからない
	char buffer[ (2+1)*4096 + (2+1)*12 + 1024 ] ;
	pring = buffer ;
	pctrl = (struct buf_ctrl *)( buffer + (2+1)*4096 +512 );

    //  リングバッファ管理テーブルの作成
    pctrl->sum = 2 ;                           //  バッファ総数の設定
    pctrl->apply_loc = 0 ;                     //  アプリケーション位置のクリア
    WAV_makeTable( pring, (char *)pctrl ) ;

    //  サンプリングデータを格納する領域の確保
    if ( (pdata = TL_malloc( pcmSize )) == NULL )
    {
		error = OUT_OF_MEMORY ;
        goto MEMFIN_2 ;
    }

    //  録音前準備
    WAV_recPrepare( freq, bitN, kind, pdata, (void (*)())NULL ) ;

    //  録音開始
    WAV_rec( WAV_REC_COMPLETE, 0, pcmSize ) ;

	short int *pD ;
	pD = ( short int * )pdata ;
	for( i=0 ; i<length ; i++ )
	{
		fftData[i] = pD[ i*2 + chMode ] ;
		if( fftData[i] & 0x80000 )
			fftData[i] |= 0xffff0000 ;
	}

    //  後処理
MEMFIN_4:;
MEMFIN_3:;
    TL_free( pdata ) ;
MEMFIN_2:;
MEMFIN_1:;

    return error ;
}

//  FFT解析のためのサンプリング HR以下
static int fftRecMemory2( int freq, int length )
{
	int kind = 1 ;              //  データ種別
	int bitN = 8 ;              //  サンプリングビット数
	int pcmSize ;               //  サンプリングデータ長
	int i ;

	pcmSize = length * (8/8) * 1 ;  //  サンプリングデータ長

    char  *pring ;                //  リングバッファポインタ
    struct  buf_ctrl
    {
        int   sum ;
        int   apply_loc ;
        int   system_loc ;
        struct
        {
            char  *ptr ;
            char  reserve[8] ;
        }   buftbl[2] ;
    }   *pctrl ;                 //  リングバッファ管理テーブルポインタ
    char  *pdata ;                //  サンプリングデータ格納領域ポインタ
    int   pcmstart ;              //  PCMデータ相対開始位置
    int   error ;

	error = NOERR ;

    //  リングバッファとリングバッファ管理テーブルの領域の確保を行う
    //  リングバッファ数は２個
// シェル対応のプログラムの場合ワークは,auto変数 or static変数を
// 使わないとWAV関数とうまくいかないこともある.何故かはわからない
	char buffer[ (2+1)*4096 + (2+1)*12 + 1024 ] ;
	pring = buffer ;
	pctrl = (struct buf_ctrl *)( buffer + (2+1)*4096 +512 );

    //  リングバッファ管理テーブルの作成
    pctrl->sum = 2 ;                           //  バッファ総数の設定
    pctrl->apply_loc = 0 ;                     //  アプリケーション位置のクリア
    WAV_makeTable( pring, (char *)pctrl ) ;

    //  サンプリングデータを格納する領域の確保
    if ( (pdata = TL_malloc( pcmSize )) == NULL )
    {
		error = OUT_OF_MEMORY ;
        goto MEMFIN_2 ;
    }

    //  録音前準備
    WAV_recPrepare( freq, bitN, kind, pdata, (void (*)())NULL ) ;

    //  録音開始

    SND_fm_timer_b_set( 0, 0 ) ;          //  音質向上の為タイマＢを停止
    WAV_rec( WAV_REC_COMPLETE, 0, pcmSize ) ;
    SND_fm_timer_b_start() ;              //  タイマＢを再起動

	for( i=0 ; i<length ; i++ )
	{
		fftData[i] = pdata[ i ] ;
		fftData[i] = ( fftData[i] - 0x80 ) << 8 ;
	}

    //  後処理
MEMFIN_4:;
MEMFIN_3:;
    TL_free( pdata ) ;
MEMFIN_2:;
MEMFIN_1:;

    return error ;
}

