home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix Heaven Sunny 2
/
APPARE2.BIN
/
oh_towns
/
gwav
/
src
/
gwav.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-20
|
34KB
|
1,113 lines
/************************************************************************/
/* PCM Player 'GWAV' V1.1 L32 */
/* */
/* 『GWAV.EXG』 */
/* */
/* Copyright(C) 1994,1995 by メルキュール */
/************************************************************************/
/* シェルアプリとしては、ほとんど最低限のことしかしていないが、とりあ */
/* えず動いているのでよしとする(メモリ不足時の動作に不安あり…ほとんど */
/* 対策とってないし) */
/* なお、本来は、SNDとWAVの資源はタスク切り替え時に退避復元してやらな */
/* くてはならないのだが、そうするとバックグラウンドで音が鳴らなくなっ */
/* てつまらないので、あえて強行している */
/* だから、ほんとはあまり真似してほしくない…(^^; */
/* それから、ところどころ現れる'EIN_'関数はEIN(TM)プロジュクトの関数群 */
/* で、終了時の座標を記憶するリジュームマネージャとして使用している */
/* GUIライブラリの関数群とは違うので、EINTM.LIBを組み込まないと使用 */
/* できない */
/* しかし、だ。WAVEに規定外の周波数のデータを放り込むとエラーで */
/* はじかれるとは知らなかったのであった(V1.1L31対応) */
/* さらにNULLポインタでcompareするバグも後から発覚(V1.1L32対応) */
/************************************************************************/
/* 注:コンパイル時にwarningが出るが、問題ないのがわかっているので無視 */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <winb.h>
#include <te.h>
#include <fntb.h>
#include <gui.h>
#include <egb.h>
#include <guidbg.h>
#include <file_dlg.h>
#include <snd.h>
#include <wav.h>
#include "eintm.h" /* EIN(TM)環境用ライブラリ */
char *guiEgbPtr ; /* EGB のワークアドレス */
/* 部品ID用変数の定義 */
int backId = -1 ;
int quitBtnId = -1 ;
int fnameBtnId = -1 ;
int fnameMesId = -1 ;
int fileSlctId = -1 ;
int wavPlayBtnId = -1 ;
int wavStopBtnId = -1 ;
/* PCMのチャネル指定 */
#define ch 69
/* リジューム情報読み書きバッファのサイズ(アプリ固有なので要調整) */
#define RBUFSIZE (1024)
int mute_data ; /* 電子ボリュームのミュート保存用 */
int wavFlag = FALSE ; /* WAVファイル再生モード */
char *wavBuffer = NULL ; /* PCMデータ格納用バッファへのポインタ */
char fileName[32] ; /* ファイル名バッファ(画面表示専用) */
char path[80] = "\0" ; /* パス名バッファ */
int freq, bitno, kind, pcmLen, pcmStart ;
/* WAVライブラリ用パラメータ */
int saveDrv ; /* カレントドライブ退避用 */
char saveDir[68] = "\0" ; /* カレントディレクトリ退避用 */
FRAME rsmFrame ; /* リジューム時に必要な部品座標 */
char RSMID[] = "%%% PCM Player GWAV %%%" ;
/* リジュームファイル用のキー文字列 */
char version[] = "PCM Player 'GWAV' V1.1L31" ;
/* バージョン表記(タスク名) */
char copyright[] = "Copyright(C)1994,1995 メルキュール(Jun Somekawa)" ;
/* Copyright表記 */
/* WAVEライブラリサポートサンプリング周波数テーブル */
int freqTbl[11] = {
8000, 9600, 11025, 12000, 16000, 19200,
22050, 24000, 32000, 44100, 48000
} ;
/* アラート用メッセージデータ */
static char *alertStr[] = {
"GWAV.EXG:\nメモリが不足しています。\n"\
"メモリを空けてから再チャレンジしましょう。",
"確認"
} ;
static char *alertStr2[] = {
"GWAV.EXG:\nWAVEファイルを再生できる状態ではありません。\n"\
"マイクロソフトウェーブフォームデータを「使用する」にしてないようです。",
"確認"
} ;
static char *alertStr3[] = {
"GWAV.EXG:\n音声ファイルが見つかりません",
"確認"
} ;
static char *alertStr4[] = {
"GWAV.EXG:\nWAVEファイルフォーマットの異常みたいです。\n"\
"これでは正常に再生できません。",
"確認"
} ;
/************************************************************************/
/* Townsシェル呼び出し関数 */
/************************************************************************/
int userFunc(apliId, messId, info, data)
int apliId ;
int messId ;
int info ;
int data ;
{
register int ret ;
POOLDATA *ptr ;
int sw ;
WINCTRL *pctrl ;
int dx, dy ;
HYPER hyp ;
extern char *splitFileName() ;
extern int cbAnalysis() ;
ret = ILLEGAL_FUNCTION ;
switch(messId)
{
/* アクティブになったときの処理 */
/* 普通はあまりGM_WAKE時の処理を記述することはない */
case GM_WAKE :
/* もし、GWAVが画面外に追い出されているような場合、 */
/* アクティブにしても操作できなくなるため、画面内に */
/* 移動する処理を行う */
dx = dy = 0 ;
MMI_GetControl(&pctrl) ; /* 画面の大きさを取得する */
MMI_SendMessage(backId, MM_GETHYPER, 1, &hyp) ;
if (hyp.fr.lupx > pctrl->bound.rdwx)
dx = pctrl->bound.rdwx - hyp.fr.lupx -
(hyp.fr.rdwx - hyp.fr.lupx) ;
if (hyp.fr.lupy > pctrl->bound.rdwy)
dy = pctrl->bound.rdwy - hyp.fr.lupy -
(hyp.fr.rdwy - hyp.fr.lupy) ;
if (dx != 0 || dy != 0)
{
/* 移動には、消去して座標移動してから表示するという */
/* 超原始的な方法を採用 */
/* ほんとはクリップをうまく使って再描画したほうが */
/* かっこいいんだけど… */
MMI_SendMessage(backId, MM_ERASE, 0) ;
MMI_SendMessage(backId, MM_MOVE, 2, dx, dy) ;
MMI_SendMessage(backId, MM_SHOW, 0) ;
}
break ;
/* メモリ不足時の処理 */
/* 他のタスクでメモリがないらしいので、解放してあげよう */
/* 後で再生するときには、また読み込めばよいのです */
case GM_PURGE :
/* PCMデータ用のバッファを持っていたら解放する */
if (wavBuffer != NULL)
{
TL_free(wavBuffer) ;
wavBuffer = NULL ; /* バッファがないので、NULLにする */
ret = NOERR ;
}
break ;
/* タスク終了時の処理 */
case GM_QUIT :
/* 再生中なら、再生を中止する */
/* 停止ボタンを押すように呼び出し関数を実行するだけ */
MMI_SendMessage(quitBtnId, MM_EXEC, 2, 0, 0) ;
ret = NOERR ;
break;
/* タスクの一時停止時の処理 */
/* GM_PAUSEのタイミングではとにかく、もとの状態に可能な限り */
/* 復元することを忘れてはいけない */
/* 他のタスクがすべての資源を専有する可能性があるので、 */
/* とにかく起動前とほぼ同じ状態に戻すよう努力する */
case GM_PAUSE :
/* 再生中なら、再生を中止する */
/* 停止ボタンを押すように呼び出し関数を実行するだけ */
MMI_SendMessage(wavStopBtnId, MM_EXEC, 2, 0, 0) ;
SND_elevol_mute(mute_data) ; /* ミュート状態を戻す */
ret = NOERR ;
break ;
/* タスクの動作再開時の処理 */
/* GM_PAUSEと反対に、自タスクが動作可能になるように処理する */
case GM_CONTINUE :
/* 再び再生可能なように再設定を行う */
mute_data = SND_get_elevol_mute(0) ;/* ミュート情報の取得 */
SND_elevol_mute(mute_data | 0x01) ; /* PCMのミュートを解除 */
ret = NOERR ;
break;
/* プールからデータの送信を受けた時の処理 */
/* GWAVではパラメータ文字列を受け取るだけ */
case GM_SENDDATA :
/* パラメータ文字列 の受け取り */
if ((ptr = (POOLDATA *)MMI_CallMessage(MMI_GetApliId(),
GM_POOLDATA, PM_POOLID, data)) != NULL)
{
if (!strcmp((char *)&ptr->Type, POOL_STR_CB))
{
sw = cbAnalysis(ptr) ;
if (sw != ILLEGAL_FUNCTION)
{
if (info == MMI_GetApliId())
{
MMI_CallMessage(MMI_GetApliId(), GM_STACKDATA,
FALSE, data) ;
}
/* pathにパラメータ文字列が入っているので、 */
/* メッセージ型部品にファイル名部分のみ設定 */
MMI_SendMessage(fnameMesId, MM_SETMSG, 1,
splitFileName(fileName, path)) ;
MMI_SendMessage(fnameMesId, MM_SHOW, 0) ;
/* PCMデータバッファを解放して、初期化する */
/* そうでないと新しいデータが読めない */
if (wavBuffer != NULL)
{
TL_free(wavBuffer) ;
wavBuffer = NULL ;
}
/* 音声再生開始 */
MMI_SendMessage(wavPlayBtnId, MM_EXEC, 2, 0, 0) ;
ret = NOERR ;
}
}
}
break ;
}
return ret ;
}
/************************************************************************/
/* main関数 */
/* GUIジェネレータでシェルアプリ用に生成した場合、こんな感じになる */
/* ただし、argcとargvは追加部分 */
/************************************************************************/
void main(int argc, char *argv[])
{
static MMICTRL mmi ={
SCREEN16 | SCREENIGNORE, /* ページ0側解像度(16色) */
SCREENUNUSED, /* ページ1側解像度 */
0, /* 書き込みページ */
SCREENAVAILABLE, /* 表示ページ(色数無依存) */
0, /* 表示プライオリティ */
SCREENAVAILABLE, /* 色数(画面枠自動設定) */
SCREENEXPAND, /* VRAMの横の長さ */
/* (解像度無依存) */
0, /* メモリ領域の大きさ */
NULL, /* メモリ領域のアドレス */
0, /* ユーザ領域の大きさ */
NULL, /* ユーザ領域のアドレス */
0, 0, /* 画面枠 lupx,lupy */
0, 0, /* rdwx,rdwy */
-16384, -16384, /* 移動枠 lupx,lupy */
16383, 16383, /* rdwx,rdwy */
15, /* 白色 */
8, /* 黒色 */
7, /* 灰色 */
7 /* 反転色 */
} ;
extern int APL_init() ;
extern int APL_end() ;
extern char *splitFileName() ;
extern char *cbSetupArea() ;
int kobj ;
/* 二重起動チェック */
/* GWAVがすでにシェル上で動作していた場合は、既存のGWAVを有効に */
/* して、後から起動したGWAVを終了する */
/* 2個以上動作しても構わないプログラムなら、この処理は不要 */
if ((kobj = MMI_CallMessage(MMI_GetApliId(),
GM_QUERYID, QM_KIND, 1)) > NOERR)
{
int id ;
char *ptr ;
if (argc > 1)
{
/* パラメータがあればPOOL機能で既存のGWAVにパラメータの */
/* 文字列を送信する */
/* ただ、GWAVではパラメータはサウンドファイル名の1個だけ */
/* なので、argv[1]だけにする */
if ((ptr = cbSetupArea(argv[1])) != NULL)
{
/* プールへデータを送る */
id = MMI_CallMessage(MMI_GetApliId(), GM_STACKDATA,
TRUE, (int)ptr) ;
TL_free(ptr) ;
/* プールにデータを送信できたら、次にそれを既存のGWAV */
/* に送信する */
if (id > NOERR)
MMI_CallMessage(kobj, GM_SENDDATA, kobj, id) ;
}
else
{
/* メモリ不足でプールに送信できなかった */
MMI_CallMessage(MMI_GetApliId(), GM_ALERT,
AM_ALERT1 | AM_ALERTB0E, (int)alertStr) ;
}
}
/* 既存のGWAVをアクティブにして、自分は終了する */
/* (二重起動の回避) */
MMI_CallMessage(MMI_GetApliId(), GM_SWITCH, FALSE, kobj) ;
return ;
}
/* 初期化処理 */
if (MMI_Open( &mmi ) == NOERR)
{
/* 初期化に成功すればメインループに入る. */
if (APL_init() == NOERR)
{
if (argc > 1)
{
/* パラメータはargv[1]の1個だけしか認識しない */
/* しかも細かいチェックはしていない */
strcpy(path, argv[1]) ;
/* 再生中のファイル名をメッセージ型に設定して表示 */
MMI_SendMessage(fnameMesId, MM_SETMSG, 1,
splitFileName(fileName, path)) ;
MMI_SendMessage(fnameMesId, MM_SHOW, 0) ;
/* 再生開始 */
MMI_SendMessage(wavPlayBtnId, MM_EXEC, 2, 0, 0) ;
}
/* メインループ突入 */
MMI_ExecSystem() ;
/* 後始末 */
APL_end() ;
}
else
{
MMI_CallMessage(MMI_GetApliId(), GM_ALERT,
AM_ALERT1 | AM_ALERTB0E, (int)alertStr) ;
}
}
/* 終了処理 */
MMI_Close() ;
}
/************************************************************************/
/* アプリケーション初期化関数 */
/************************************************************************/
int APL_init()
{
extern MMIINIT initDataIGWAV ;
extern void centeringFunc() ;
register int ret ;
char einWork[RSMWORKSIZE] ; /* リジュームマネージャのワークエリア */
char buf[RBUFSIZE] ; /* リジュームデータ読み込みバッファ */
char *ptr ; /* タグ検索時に利用するポインタ */
int size, x, y;
HYPER hyp ;
/* EGB ワークアドレスの取得. */
guiEgbPtr = MMI_GetEgbPtr() ;
/* ハイパ型部品の初期化 */
if ((ret = MMI_initHyper()) < 0)
return ret ;
/* ダイアログ型部品の初期化 */
if ((ret = MMI_initDialogL40()) < 0)
return ret ;
/* アラート型部品の初期化 */
if ((ret = MMI_initAlertL40()) < 0)
return ret ;
/* メッセージ型部品の初期化 */
if ((ret = MMI_initMessageL40()) < 0)
return ret ;
/* ボタン型部品の初期化 */
if ((ret = MMI_initButtonL40()) < 0)
return ret ;
/* ドロウボタン型部品の初期化 */
if ((ret = MMI_initDrawButtonL40()) < 0)
return ret ;
/* アイコンボタン型部品の初期化 */
if ((ret = MMI_initIconL40()) < 0)
return ret ;
/* スクロール型部品の初期化 */
if ((ret = MMI_initScrollBarL40()) < 0)
return ret ;
/* テキスト型部品の初期化 */
if ((ret = MMI_initTextL40()) < 0)
return ret ;
/* リストメニュー型部品の初期化 */
if ((ret = MMI_initListMenuL40()) < 0)
return ret ;
/* 背景データの初期化 */
/* データの登録 */
if ((ret = MMI_Init(&initDataIGWAV)) < 0)
return ret ;
/* ファイルダイアログライブラリの初期化処理 */
/* ファイルダイアログがカレントを変更するため、起動時のカレント */
/* ドライブとカレントディレクトリを保存 */
FDG_SaveCurDir() ;
/* ファイルダイアログライブラリの初期化 */
/* 初期化を行わないと正常に動作しない */
/* 戻り値をチェックするのを忘れないこと */
if ((ret = FDG_InitFileDlg()) < 0)
return ret ;
/* リジュームマネージャの初期化(アプリのIDタグ登録) */
size = 0 ;
/* 失敗(0以外)だったらCD起動なのでリジュームしない */
if (EIN_rsmInit(einWork, RSMID) == 0)
{
/* 読み込みバッファの設定 */
EIN_rsmBufSet(einWork, buf, RBUFSIZE) ;
/* リジューム情報読み込み */
size = EIN_rsmLoad(einWork) ;
}
/* ちゃんと読み込めたなら size>0 になるので、設定を変更します */
if (size > 0)
{
/* ダイアログ(PANEL)表示位置を、リジューム情報を元に設定 */
if (((ptr = strstr(buf,"\nPANEL: ")) != NULL ) &&
(sscanf(ptr,"\nPANEL: %d %d\n", &x, &y) > 1))
{
MMI_SendMessage(backId, MM_GETHYPER, 1, &hyp) ;
rsmFrame.lupx = x ;
rsmFrame.lupy = y ;
rsmFrame.rdwx = x + (hyp.fr.rdwx - hyp.fr.lupx) ;
rsmFrame.rdwy = y + (hyp.fr.rdwy - hyp.fr.lupy) ;
if (x < -31)
x = 0 ;
if (y < -31)
y = 0 ;
MMI_SendMessage(backId, MM_MOVE, 1, &rsmFrame) ;
}
}
else
{
/* デフォルトの起動時は必ず画面中央 */
/* リジュームファイルが見つからなかったときは画面中央に表示 */
centeringFunc(backId) ;
}
/* GUI色をメニュー色に設定 */
/* GUIの色変換テーブルを変更して、どの画面モードでもメニュー色に */
/* なるよう設定する */
EIN_initGuiColor() ;
/* 背景を表示する */
MMI_SendMessage(MMI_GetBaseObj(), MM_SHOW, 0) ;
/* Townsシェル呼び出し関数(ユーザー関数)の設定 */
MMI_SendMessage(MMI_GetBaseObj(), MM_SETEXEC, 1, userFunc);
/* タスク名の設定 */
MMI_CallMessage(MMI_GetApliId(), GM_TITLE, (int)version, 0);
mute_data = SND_get_elevol_mute(0) ; /* ミュート情報の取得 */
SND_elevol_mute(mute_data | 0x01) ; /* PCMのミュートを解除 */
return NOERR ;
}
int APL_end()
{
SND_elevol_mute(mute_data) ; /* ミュート状態を元に戻す */
/* ファイルダイアログライブラリの終了処理 */
/* ファイルダイアログのメモリ解放 */
/* FDG_InitFileDlg関数と対にして使用する関数 */
FDG_FreeFileDlg() ;
/* 起動時のカレントドライブとカレントディレクトリを復帰 */
/* FDG_SaveCurDir関数と対にして使用する関数 */
FDG_RecovCurDir() ;
return NOERR;
}
/************************************************************************/
/* ここからサブプログラム部 */
/* 呼び出し関数や個々の関数などの記述 */
/************************************************************************/
/************************************************************************/
/* 部品を画面中央に移動させる関数 */
/* 親部品を指定すれば子部品も移動する */
/************************************************************************/
void centeringFunc(kobj)
int kobj ;
{
int dx, dy ;
HYPER hyp ;
WINCTRL *pctrl ;
/* WINCTRL構造体から画面最大サイズ(現在の解像度)を取得する */
MMI_GetControl(&pctrl) ;
/* 解像度にあわせて画面中央に移動させる */
MMI_SendMessage(kobj, MM_GETHYPER, 1, &hyp) ;
dx = (pctrl->bound.rdwx - hyp.fr.lupx - hyp.fr.rdwx) / 2 ;
dy = (pctrl->bound.rdwy - hyp.fr.lupy - hyp.fr.rdwy) / 2 ;
MMI_SendMessage(kobj, MM_MOVE, 2, dx, dy) ;
}
/************************************************************************/
/* フルパスからファイル名を切り出す */
/* (12文字に納まるようスペースで補完) */
/************************************************************************/
char *splitFileName(char *fName, char *fullPath)
{
register char *ptr ;
char space[] = " " ;
/* fullPathの後ろから前に1文字ずつパス区切り記号'\'を探すため、 */
/* fullPathの一番最後の文字へのポインタを求める */
ptr = fullPath + strlen(fullPath) - 1 ;
do
{
/* 文字が'\'で、なおかつその直前の文字が全角1バイト目でないか */
/* 調べる(全角2バイト目の'\'である可能性を調べる) */
/* 全角1バイト目かどうか調べるにはFNT_iskanjiマクロを使用する */
if (*ptr == '\\' && !FNT_iskanji(*(ptr - 1)))
{
/* '\'の直前が全角1バイト目でなければ、パス区切り記号と */
/* 判断し、ptr変数が示す文字を'\'の直後の文字(ファイル名の */
/* 先頭)にしてから、ループを脱出 */
ptr++ ;
break ;
}
ptr-- ;
}
while (ptr > fullPath) ;
/* fullPathに正しくフルパスで入っていれば、この終了条件を満たして */
/* ループを終了するのではなく、途中のif文の条件で脱出するはず */
/* ファイル名部分の位置が分かったので、それ以降の文字列をコピー */
strcpy(fileName, ptr) ;
strcat(fName, space) ; /* この方法好きじゃないんだけど・・・ */
fName[12] = '\0' ; /* High-Cのライブラリバグってるからねぇ */
return fName ;
}
/************************************************************************/
/* ファイルダイアログ処理関数 */
/* 呼び出すとファイルダイアログを表示してパス名を取得 */
/************************************************************************/
int fdlgFunc(pPathName)
char *pPathName ; /* パス名を格納する配列 */
{
static char *ExtStr[3] = { "*.SND", "*.WAV", NULL } ;
/* ワイルドカードの指定 */
unsigned int MSlctCnt ; /* 選択されたファイル数 */
unsigned int InfSw ; /* 表示属性 */
int Atr ; /* ファイル属性 (未使用) */
int ret ;
int capa ;
/* WAVライブラリが使えないなら、.WAV選択不可とする */
if (WAV_getCapability(&capa, 19200) != 0)
ExtStr[1] = NULL ;
/* ファイルダイアログの表示 */
/* 読込時にはファイル名テキスト入力不可にする */
/* サブディレクトリは選択できない(FDG_FILEONLY) */
/* ファイルが選択されない時実行ボタンを押せない(FDG_SLCTCHK) */
/* ついでにタスク切替え禁止(FDG_ALERT) */
InfSw = FDG_FILEONLY | FDG_SLCTCHK | FDG_REDRAW | FDG_ALERT ;
/* ファイルダイアログのタイトルを設定する */
FDG_SetTitle("サウンド読込", "読 込", "取 消") ;
/* 退避したカレントディレクトリを復元して、ファイルダイアログ準備 */
/* ファイルダイアログは、カレントディレクトリのファイル一覧を表示 */
/* する仕様 */
FM_SelectDisk(saveDrv) ;
FM_SetCurrentDir(saveDir) ;
/* ファイルダイアログ表示 */
ret = FDG_DspFileDlg(backId, InfSw, NULL, ExtStr, &MSlctCnt) ;
/* カレントディレクトリを退避 */
/* また後でファイルダイアログを表示するときに、直前までと同じ */
/* ディレクトリを表示するために必要 */
saveDrv = FM_GetCurrentDisk() ;
FM_GetCurrentDir(saveDrv, saveDir) ;
if (ret && MSlctCnt > 0)
{
/* "読込"が押され、なおかつファイルが選択されていたならば、 */
/* ファイル名を取得する */
FDG_GetPathName(pPathName, &Atr, 0) ;
}
else
{
/* "取消"が押されたか1つもファイルが選択されなかった場合は */
/* ファイル名を取得しないで終了する */
ret = 0 ;
}
return ret ;
}
/************************************************************************/
/* "CB"形式のプールデータを解析 */
/* 実はこの関数、プール用サンプルとほぼ同じもの */
/* (どう処理したらいいのかマニュアルとか見ただけじゃわかんない(^^;) */
/************************************************************************/
int cbAnalysis(ptr)
POOLDATA *ptr ;
{
int ret = ILLEGAL_FUNCTION ;
size_t size, len ;
unsigned char *rec, *work ;
unsigned short tag ;
if (ptr->Kind & POOL_REAL)
{
/* テキストブロックの先頭アドレスを探す */
if (POL_cbSearchBlock((unsigned char *)ptr->dPtr, PCBF_TEXT, 1,
&rec, &size))
{
work = POL_cbGetRecSize(rec, &len) ;
/* タグ解析中 */
do
{
tag = *(unsigned short *)work ;
work = POL_cbGetRecSize(work, &len) ;
/* テキストファイル名か? */
if ((tag & 0xff) == PCBF_TEXTFILE)
{
/* ファイル名設定 */
strcpy(path, (char *)work) ;
ret = 0 ;
}
work += len ;
}
while ((tag & 0xff) != 0x1f) ; /* データレコード終了 */
}
}
return ret ;
}
/************************************************************************/
/* プールデータヘッダ用領域とCB用領域を確保/初期化/ファイル名設定 */
/* 実はこの関数も、プール用サンプルとほぼ同じもの */
/* (どう処理したらいいのかマニュアルとか見ただけじゃわかんない(^^;) */
/************************************************************************/
char *cbSetupArea(setupStr)
char *setupStr ;
{
typedef struct _CB_SMPTEXT {
CB_TAG_LONG Main ;
CB_TAG Sub ;
unsigned short SubId ;
CB_TAG Text ;
} CB_SMPTEXT ;
char *ret = NULL ;
char *ptr ;
POOLDATA *pol ;
unsigned char *text, *addrec, *cb ;
size_t hSize, cbSize, tSize, nSize = 80 ;
char str[16] ;
/* テキストブロックの大きさを計算する */
tSize = sizeof(CB_SMPTEXT) + sizeof(CB_TAG) + nSize ;
/* "CB"型データ全体の大きさを計算する */
cbSize = PCB_DEF_SIZE + PCB_MREC_SIZE * 2 + tSize ;
/* プールデータヘッダ用領域の大きさ */
hSize = sizeof(POOLDATA) ;
/* メモリ獲得時に一定のメモリを残しておく */
if ((TL_checkMemory(1) * 4096) > (1024 * 16 + hSize + cbSize))
{
if ((ptr = TL_malloc(hSize + cbSize))==NULL)
return ret ;
/* 確保したメモリの先頭をプールデータヘッダ用に */
/* 残りを"CB"領域に使用する */
pol = (POOLDATA *)ptr ;
cb = (unsigned char *)(ptr + hSize);
/* プールヘッダの設定 */
MMI_CallMessage(MMI_GetApliId(),GM_QUERYID, QM_FILENAME, (int)str) ;
strcpy((char *)&pol->Creator, str) ; /* データ本体編集者 */
strcpy((char *)&pol->Owner, str) ; /* プールデータ作成者 */
strcpy((char *)&pol->Type, POOL_STR_CB) ; /* データ型 */
pol->apliId = MMI_GetApliId() ; /* プールデータ作成者 */
/* アプリケーションID */
pol->Kind = POOL_REAL ; /* データ種別 */
pol->dPtr = (void *)cb ; /* データサイズ */
pol->dSize = cbSize ; /* データ本体ポインタ */
/* "CB"型アクセス用関数を使用して */
/* "CB"用に確保した領域を"CB"領域として初期化する */
if (!POL_cbInit(cb, 2, cbSize, 0))
{
/* "CB"領域にテキストブロックを登録する */
if (!POL_cbAddBlock(cb, PCBF_TEXT, tSize, &text))
{
/* テキストブロックにレコードを追加する */
POL_cbAddRec(text, PCBF_TEXTKIND, 0, 2, &addrec) ;
*(unsigned short *)addrec = 0 ;
POL_cbAddRec(text, PCBF_TEXTFILE, 0, nSize, &addrec) ;
strcpy((char *)addrec, setupStr) ;
ret = ptr ;
}
}
/* "CB"領域の設定に失敗した場合は、確保した領域を解放する */
if (!ret)
TL_free(ptr) ;
}
return ret ;
}
/************************************************************************/
/* リジューム情報の更新 */
/* EIN(TM)環境用ライブラリのリジュームマネージャを使用 */
/************************************************************************/
void saveResumeFile()
{
char work[RSMWORKSIZE] ; /* リジュームマネージャワーク */
char buf[RBUFSIZE] ; /* リジュームデータセーブバッファ */
char aplPath[128] ; /* アプリディレクトリパス名 */
HYPER hyp ;
/* リジュームマネージャの初期化に失敗したらセーブできないので終了 */
/* 失敗(0以外)だったらCD起動なのでリジュームしない */
if (EIN_rsmInit(work, RSMID) != 0)
return ;
/* パネルの枠座標を得る */
MMI_SendMessage(backId, MM_GETHYPER, 1, &hyp) ;
/* 設定が変化していた(ユーザーが部品を移動した)ら保存する */
if ((rsmFrame.lupx != hyp.fr.lupx) || (rsmFrame.lupy != hyp.fr.lupy))
{
/* バッファ設定(アプリ識別IDと更新時刻を自動設定する) */
EIN_rsmBufSet(work, buf, RBUFSIZE) ;
/* アプリディレクトリ保存 */
MMI_CallMessage(MMI_GetApliId(), GM_QUERYID, QM_PATH, (int)aplPath) ;
EIN_rsmBufPrintf(work, "APLPATH: %s", aplPath) ;
/* アプリ名保存 */
EIN_rsmBufPrintf(work, "TITLE: %s", version) ;
/* コメント保存 */
EIN_rsmBufCat(work, "COMMENT: SND/WAV音声データプレイヤーです。") ;
/* 位置保存 */
EIN_rsmBufPrintf(work, "PANEL: %d %d", hyp.fr.lupx, hyp.fr.lupy) ;
/* バッファ終端設定 */
EIN_rsmBufTail(work) ;
/* バッファの内容を保存 */
/* (バッファの容量が足りないと失敗するので、容量を増やして */
/* retryするべき…らしいんだけど、やってなかったりする(^^;) */
/* バッファサイズ固定にしちゃってるし… */
EIN_rsmSave(work) ;
/* リジュームした座標を保存しておく(移動したかどうかの判定) */
rsmFrame = hyp.fr ;
}
}
/************************************************************************/
/* 終了ボタンを押すと実行する呼び出し関数 */
/* initDataIGWAV:quitBtnId:MJ_ICONL40の呼び出し関数 */
/************************************************************************/
int quitFunc(kobj, messId, argc, pev, trigger)
int kobj ;
int messId ;
int argc ;
EVENT *pev ;
int trigger ;
{
/* リジュームを行う(EIN(TM)リジュームマネージャ使用) */
saveResumeFile() ;
/* 停止ボタンを押して、再生を停止する */
MMI_SendMessage(wavStopBtnId, MM_EXEC, 2, 0, 0) ;
/* PCMデータバッファを解放 */
/* 解放を忘れると、メモリが残ったままプログラムが終わるので、PCM */
/* データバッファ分だけフリーエリアが減ってしまう */
if (wavBuffer != NULL)
TL_free(wavBuffer) ;
/* プログラムを終了 */
MMI_SetHaltFlag(TRUE) ;
return NOERR ;
}
/************************************************************************/
/* 再生ボタンを押すと実行する呼び出し関数 */
/* initDataIGWAV:wavPlayBtnId:MJ_ICONL40の呼び出し関数 */
/************************************************************************/
int wavPlayFunc(kobj, messId, argc, pev, trigger)
int kobj ;
int messId ;
int argc ;
EVENT *pev ;
int trigger ;
{
FILE *fp ;
int note ;
int stackPtr ;
int rdSize ;
int ret ;
int capa ;
char *ptr ;
/* 停止ボタンを押して、再生を停止する */
MMI_SendMessage(wavStopBtnId, MM_EXEC, 2, 0, 0) ;
/* 拡張子を探そう */
/* '.'がなければ終わってしまう */
if ((ptr = strrchr(path, '.')) == NULL)
return NOERR ;
/* 拡張子が.WAVならば、wavFlagをONにして、WAV再生モードに入る */
if (strcmp(ptr, ".WAV") == 0)
{
/* WAV再生が不可な状態にあるならば、なにもせず処理を終了 */
if (WAV_getCapability(&capa, 19200) == 0)
{
wavFlag = TRUE ;
}
else
{
/* WAVが再生可能ではないのに無理やり再生しようとした */
MMI_CallMessage(MMI_GetApliId(), GM_ALERT,
AM_ALERT1 | AM_ALERTB0E, (int)alertStr2) ;
return NOERR ;
}
}
else
{
wavFlag = FALSE ;
}
/* PCMデータバッファを確保していなければ、確保してデータを読み込む */
if (wavBuffer == NULL)
{
/* パスが指定されてなければ、なにもしない */
if (path[0] == '\0')
return NOERR ;
/* マウスカーソルを時計マークにする */
MG_PushPtr(MB_WAIT, &stackPtr) ;
/* データファイルをオープン */
if ((fp = fopen(path, "rb")) == 0)
{
/* マウスカーソルを元に戻す */
MG_PopPtr(stackPtr) ;
/* 音声ファイルが見つからない */
MMI_CallMessage(MMI_GetApliId(), GM_ALERT,
AM_ALERT1 | AM_ALERTB0E, (int)alertStr3) ;
return NOERR ;
}
/* WAV再生モード */
if (wavFlag == TRUE)
{
rdSize = 0 ;
/* WAVファイルのヘッダから、必要な情報を得る */
/* ヘッダのサイズが不定なので、正常に読み込めるまでループ */
do
{
char *tmpPtr ;
rdSize += 50 ;
fseek(fp, 0, SEEK_SET) ;
/* ヘッダバッファの取得 */
if ((tmpPtr = TL_malloc(rdSize)) == NULL)
{
/* データファイルをクローズ */
fclose(fp) ;
/* マウスカーソルを元に戻す */
MG_PopPtr(stackPtr) ;
/* メモリが足りない */
MMI_CallMessage(MMI_GetApliId(), GM_ALERT,
AM_ALERT1 | AM_ALERTB0E, (int)alertStr) ;
return NOERR ;
}
fread(tmpPtr, sizeof(char), rdSize, fp) ;
ret = WAV_getWaveInfo(tmpPtr, rdSize, &freq, &bitno,
&kind, &pcmLen, &pcmStart) ;
/* いらなくなったので、ヘッダバッファを解放 */
TL_free(tmpPtr) ;
}
while (ret == 23) ;
}
/* SND再生モード */
else
{
fseek(fp, 0, SEEK_END) ;
pcmLen = (unsigned int)ftell(fp) ;
fseek(fp, 0, SEEK_SET) ;
}
/* 必要なバッファサイズが判明したので、メモリを確保 */
if ((wavBuffer = TL_malloc(pcmLen)) == NULL)
{
/* データファイルをクローズ */
fclose(fp) ;
/* マウスカーソルを元に戻す */
MG_PopPtr(stackPtr) ;
/* メモリが足りない */
MMI_CallMessage(MMI_GetApliId(), GM_ALERT,
AM_ALERT1 | AM_ALERTB0E, (int)alertStr) ;
return NOERR ;
}
/* 念のためバッファ内を初期化する(TL_mallocは0クリア保証なし) */
memset(wavBuffer, 0, pcmLen) ;
/* WAVなら、WAVデータ本体の先頭にシーク */
/* WAVの先頭のヘッダ部分は飛ばして読み込まなくてはならない点に */
/* 注意すること */
if (wavFlag == TRUE)
fseek(fp, pcmStart, SEEK_SET) ;
/* データの読み込み */
fread(wavBuffer, sizeof(char), pcmLen, fp) ;
/* データファイルをクローズ */
fclose(fp) ;
/* マウスカーソルを元に戻す */
MG_PopPtr(stackPtr) ;
}
if (wavFlag == TRUE)
{
/* WAV再生準備 */
ret = WAV_playPrepare(freq, bitno, kind, wavBuffer, (void (*)())NULL) ;
if (ret == 21)
{
/* 再生周波数がサポートしているものと違う場合、エラー */
/* でも、近い周波数で再生してくれると嬉しい */
int i, prevAbs ;
if (freq < freqTbl[0])
{
/* アンダーフローは、全部一番低いサンプリング周波数に */
freq = freqTbl[0] ;
}
else if (freq > freqTbl[10])
{
/* オーバーフローは、全部一番高いサンプリング周波数に */
freq = freqTbl[10] ;
}
else
{
/* 中間なら近いものを探し出す */
prevAbs = abs(freq - freqTbl[0]) ;
for (i = 1; i < 11; prevAbs = abs(freq - freqTbl[i]), i++)
{
/* 前のほうが近かったぞ */
if (prevAbs < abs(freq - freqTbl[i]))
break ;
}
freq = freqTbl[i - 1] ;
}
/* WAV再生準備(逆襲の周波数編) */
ret = WAV_playPrepare(freq, bitno, kind, wavBuffer,
(void (*)())NULL) ;
}
if (ret != 0)
{
/* 再生準備(WAV_playPrepare)に失敗したから再生できず */
MMI_CallMessage(MMI_GetApliId(), GM_ALERT,
AM_ALERT1 | AM_ALERTB0E, (int)alertStr4) ;
TL_free(wavBuffer) ;
wavBuffer = NULL ;
return NOERR ;
}
WAV_setVolume(127, 127) ; /* ボリュームを最大に */
WAV_play(pcmLen) ; /* WAVの再生開始 */
}
else
{
SND_pcm_mode_set(3) ; /* PCMの3チャンネルが音声モード */
note = (char)wavBuffer[28] ; /* サウンドデータ基本音階の取得 */
SND_pcm_play(ch, note, 127, wavBuffer) ;
/* SNDの再生開始 */
/* (ボリュームは最大) */
}
return NOERR ;
}
/************************************************************************/
/* ファイル選択ボタンを押すと実行する呼び出し関数 */
/* initDataIGWAV:fileSlctId:MJ_ICONL40の呼び出し関数 */
/************************************************************************/
int loadFunc(kobj, messId, argc, pev, trigger)
int kobj ;
int messId ;
int argc ;
EVENT *pev ;
int trigger ;
{
/* ファイルダイアログで何も選択されなかったらそのまま終了 */
if (fdlgFunc(path) == 0)
return NOERR ;
/* ファイル名をメッセージ型部品に設定 */
MMI_SendMessage(fnameMesId, MM_SETMSG, 1, splitFileName(fileName, path)) ;
MMI_SendMessage(fnameMesId, MM_SHOW, 0) ;
/* PCMデータバッファの解放 */
TL_free(wavBuffer) ;
wavBuffer = NULL ;
/* 音声再生開始 */
MMI_SendMessage(wavPlayBtnId, MM_EXEC, 2, 0, 0) ;
return NOERR ;
}
/************************************************************************/
/* 停止ボタンを押すと実行する呼び出し関数 */
/* initDataIGWAV:wavStopBtnId:MJ_ICONL40の呼び出し関数 */
/************************************************************************/
int wavStopFunc(kobj, messId, argc, pev, trigger)
int kobj ;
int messId ;
int argc ;
EVENT *pev ;
int trigger ;
{
/* WAV再生モード時 */
if (wavFlag == TRUE)
{
int status ;
WAV_playStop() ; /* WAV再生を止める */
/* WAV再生終了を待つ */
do
{
WAV_getStatus(&status) ;
}
while (status & WAV_ST_PLAY_PLAYING) ;
/* WAV再生可能状態に戻るのを待つ */
do
{
WAV_getStatus(&status) ;
}
while (status & WAV_ST_PLAY_PROCESS) ;
/* WAVをリセットして以後の処理が正常に行えるようにする */
WAV_reset() ;
WAV_setVolume(127, 127) ;
SND_pcm_sound_delete(-1) ;
}
/* SND再生モード時 */
else
{
SND_pcm_play_stop(ch) ; /* SND再生を止める */
while (SND_pcm_status(ch)) /* SND再生終了を待つ */
;
SND_pcm_sound_delete(-1) ;
}
return NOERR ;
}