home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pleasure 76
/
OTACD76.bin
/
archive
/
game
/
PsrSDK16a
/
PsrSDK16a.lzh
/
Sample
/
PsrXaCd
/
Plugin.c
< prev
Wrap
C/C++ Source or Header
|
2000-11-20
|
18KB
|
574 lines
/******************************************************************************/
/* */
/* [PS XAプラグイン] */
/* */
/* FILE NAME : Plugin.c */
/* FUNCTION : 標準XAアクセス (CD-ROM用) */
/* */
/* FUNCTIONS | an outline */
/* --------------------------+-------------------------------------------- */
/* PsrQueryPlugin() | プラグイン情報の取得 */
/* PsrIsSupportCDBegin() | CDサポート判定 開始処理 */
/* PsrIsSupportCDEnd() | CDサポート判定 終了処理 */
/* PsrIsSupportCDSector() | CDサポート判定 セクタ通知 */
/* PsrIsSupportCDResult() | CDサポート判定 結果取得 */
/* PsrGetStrDataInfo() | ストリームデータ情報の取得 */
/* PsrOpenCD() | CDストリームのオープン */
/* PsrClose() | ストリームデータのクローズ */
/* PsrRead() | ストリームデータの読み取り */
/* PsrSeek() | 読み取り位置の設定 */
/* */
/* HISTORY | Comment | Name */
/* ------------------+---------------------------------------+------------ */
/* 2000.07.16 | 新規作成 | ふぃろ */
/* 2000.07.19 | STRの最後のXA部を拾っちゃう件 1.01 | ふぃろ */
/* 2000.07.20 | STRの終端判定を強化 1.02 | ふぃろ */
/* 2000.07.21 | セクタ数不良を修正 1.03 | ふぃろ */
/* 2000.08.08 | STRのXA部を拾っちゃう件2 1.04 | ふぃろ */
/* 2000.08.10 | チャンネル番号判定修正 1.05 | ふぃろ */
/* 2000.10.28 | プラグイン仕様変更 1.10 | ふぃろ */
/* 2000.11.14 | 誤認識対策 1.11 | ふぃろ */
/* */
/* (C) Copyright ふぃろ 2000. All rights reserved. */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <Windows.h>
#include "CdAccess.h"
#include "PSRP.h"
static LONG alZERO[] = {0, 0, 0, 0, 0, 0, 0, 0};
typedef struct { // サブヘッダー ----------------------------------------
USHORT usChaNo; // チャンネル番号
BYTE bfType; // タイプ
BYTE bfFlags; // フラグ
} _TSUBHEADER, *_PTSUBHEADER;
typedef struct { // セクター構造 ----------------------------------------
BYTE abSync[12]; // CD-ROM XA 同期
BYTE abHeader[4]; // CD-ROM XA ヘッダー
_TSUBHEADER asubH[2]; // CD-ROM XA サブヘッダー 1.05
BYTE abAudio[0x900]; // XA AUDIO
BYTE abEdc[4]; // CD-ROM XA EDC
} _TSECTOR, *_PTSECTOR;
typedef struct { // ストリーム情報 --------------------------------------
DWORD dwBegin; // データ開始セクタ番号
DWORD nLength; // データセクタ数
USHORT usChannels; // チャンネル数 1.05
USHORT usChaNo; // チャンネル番号 1.05
BYTE bFlags; // フラグ
BYTE bEnded; // 完了フラグ
DWORD nLast; // 最終セクタ 1.11
DWORD nLastGood; // 最終有効セクタ 1.11
} _TSTREAM, *_PTSTREAM;
typedef struct { // ストリーム探索ハンドルの内容 ------------------------
INT iBuffer; // ストリームバッファ数
INT iNum; // ストリーム数
INT iNumChannels; // XAチャンネル数
_PTSTREAM pstr; // ストリーム情報群
} _TFIND, *_PTFIND;
typedef struct { // ストリームハンドルの内容 ----------------------------
HANDLE hCdrom; // CD-ROMハンドル
DWORD nBegin; // ストリーム開始セクタ
DWORD nAllSector; // セクタ数
DWORD nSamplingRate; // サンプリングレート
WORD wChannels; // チャンネル数
WORD wStep; // セクタ間隔
_TSUBHEADER subH; // サブヘッダ
_PTSECTOR apSector[2]; // 退避セクタ
} _THANDLE, *_PTHANDLE;
/******************************************************************************/
/* */
/* PsrQueryPlugin() : プラグイン情報の取得 */
/* */
/******************************************************************************/
CEXPORT VOID PsrQueryPlugin(
LPPSRPLUGIN lpPlugin) // プラグイン情報取得バッファアドレス
{
strcpy(lpPlugin->aName, "XA CD-ROM");
strcpy(lpPlugin->aCopyright, "Copyright (c) Fyiro 2000.");
lpPlugin->usVersion = 111;
lpPlugin->usIsSupportVersion = 0;
lpPlugin->usSystemVersion = PSR_SYSTEMVERSION;
strcpy(lpPlugin->aSiteName, "Fyiro's Garage"); // 1.10
strcpy(lpPlugin->aSiteUrl, "http://homepage2.nifty.com/~mkb/"); // 1.10
}
/******************************************************************************/
/* */
/* PsrIsSupportCDBegin() : CDサポート判定 開始処理 */
/* */
/******************************************************************************/
CEXPORT HANDLE PsrIsSupportCDBegin(
INT iNumToc, // TOCの数
LPTOCENTRY lptoc) // TOC
{
_PTFIND pfind;
INT i;
for(i=0; i<iNumToc; i++) {
if(lptoc[i].bAdr & 0x04) break;
}
if(i == iNumToc) return NULL;
if(!(pfind = malloc(sizeof(_TFIND)))) return NULL;
// ハンドルの作成と初期設定 ----------------------------
pfind->iBuffer = 64;
pfind->iNum = 0;
pfind->iNumChannels = 0;
pfind->pstr = malloc(sizeof(_TSTREAM) * pfind->iBuffer);
if(!pfind->pstr) {
free(pfind);
return NULL;
}
return pfind;
}
/******************************************************************************/
/* */
/* PsrIsSupportCDEnd() : CDサポート判定 終了処理 */
/* */
/******************************************************************************/
CEXPORT VOID PsrIsSupportCDEnd(
HANDLE hIsCD) // CDサポート判定ハンドル
{
_PTFIND pfind;
if(!(pfind = hIsCD)) return;
free(pfind->pstr);
free(pfind);
}
/******************************************************************************/
/* */
/* PsrIsSupportCDSector() : CDサポート判定 セクタ通知 */
/* */
/******************************************************************************/
typedef struct {
ULONG aulCode[4];
BYTE abData[112];
} _ADPCM, *_PADPCM;
static BOOL _psrIsGoodAudio(_PADPCM padpcm);
CEXPORT BOOL PsrIsSupportCDSector(
HANDLE hIsCD, // CDサポート判定ハンドル
TOCENTRY toc, // TOC
DWORD nSector, // セクタ番号
PVOID pvSector) // セクタ
{
_PTFIND pfind;
_PTSECTOR psector;
_PTSTREAM pstr;
INT i;
USHORT usNum;
if(!(pfind = hIsCD)) return FALSE;
if(!(toc.bAdr & 0x04)) return FALSE; // CD-DA
if(!(psector = pvSector)) {
for(i=pfind->iNum-1; i>=0; i--) {
if(!pfind->pstr[i].bEnded) {
pfind->pstr[i] = pfind->pstr[pfind->iNum-1];
pfind->iNum --;
}
}
pfind->iNumChannels = 0;
return FALSE;
}
// XAのセクタではない ----------------------------------
if(memcmp(psector->abAudio, alZERO, sizeof(alZERO)) == 0 ||
(psector->asubH[0].bfType == 0 && psector->asubH[0].bfFlags == 0)) {
return TRUE; // ダミー
}
if((psector->asubH[0].bfType & 0x7f) != 0x64) { // 1.11 ------->
pstr = pfind->pstr;
for(i=0; i<pfind->iNum; i++) {
if(!pstr[i].bEnded && pstr[i].nLength != 1) {
usNum = (USHORT)(nSector - pstr[i].nLast);
if(usNum >= pstr[i].usChannels) {
pstr[i].bEnded = 1;
if(!pstr[i].nLastGood) {
pstr[i] = pstr[pfind->iNum-1];
pfind->iNum --;
i --;
}
pfind->iNumChannels --;
}
}
}
return TRUE;
} // <------- 1.11
// ストリーム情報の探索 --------------------------------
for(pstr=NULL, i=0; i<pfind->iNum; i++) {
if(!pfind->pstr[i].bEnded &&
pfind->pstr[i].usChaNo == psector->asubH[0].usChaNo) {
pstr = &pfind->pstr[i];
break;
}
}
if(!pstr) { // ストリーム追加 --------------------------------------
if(pfind->iBuffer == pfind->iNum) {
pfind->iBuffer += 16;
pstr = realloc(pfind->pstr,
sizeof(_TSTREAM) * pfind->iBuffer);
if(!pstr) {
pfind->iBuffer -= 16;
return TRUE; // とりあえず正常終了
}
pfind->pstr = pstr;
}
pstr = &pfind->pstr[pfind->iNum];
pstr->dwBegin = nSector;
pstr->nLength = 0;
pstr->usChannels= 1; // 1.03
pstr->usChaNo = psector->asubH[0].usChaNo;
pstr->bFlags = psector->asubH[0].bfFlags;
pstr->bEnded = 0;
pstr->nLast = 0; // 1.11
pstr->nLastGood = 0; // 1.11
pfind->iNum ++;
pfind->iNumChannels ++;
}
if(pstr->nLength == 1) {
pstr->usChannels = (USHORT)(nSector - pstr->dwBegin);
}
pstr->nLast = nSector; // 1.11
// 音声データが有効なセクタであるか判定 ----------- 1.11
if(_psrIsGoodAudio((_PADPCM)psector->abAudio)) {
pstr->nLastGood = nSector;
}
pstr->nLength ++;
// XAストリームの終了コード ----------------------------
if(psector->asubH[0].bfType & 0x80) {
pstr->bEnded = 1;
if(!pstr->nLastGood) {
*pstr = pfind->pstr[pfind->iNum-1];
pfind->iNum --;
}
pfind->iNumChannels --;
return TRUE;
}
return TRUE;
}
//****--------------------------------------------------------------------------
//**** _psrIsGoodAudio() : 音声データが有効か判定
//****--------------------------------------------------------------------------
static BOOL _psrIsGoodAudio(_PADPCM padpcm) {
INT i, j;
for(i=0; i<18; i++) {
if((padpcm->aulCode[0] && padpcm->aulCode[0] != 0x0c0c0c0c) ||
(padpcm->aulCode[1] && padpcm->aulCode[1] != 0x0c0c0c0c) ||
(padpcm->aulCode[2] && padpcm->aulCode[2] != 0x0c0c0c0c) ||
(padpcm->aulCode[3] && padpcm->aulCode[3] != 0x0c0c0c0c)) {
return TRUE;
}
for(j=0; j<112; j++) {
if(padpcm->abData[j]) return TRUE;
}
padpcm ++;
}
return FALSE;
}
/******************************************************************************/
/* */
/* PsrIsSupportCDResult() : CDサポート判定 結果取得 */
/* */
/******************************************************************************/
CEXPORT INT PsrIsSupportCDResult(
HANDLE hIsCD, // CDサポート判定ハンドル
INT iIndex, // ストリームインデックス
LPPSRSTREAMINFO lpStreamInfo) // ストリームデータ情報
{
_PTFIND pfind;
_PTSTREAM pstr;
if(!(pfind = hIsCD)) return 0;
if(pfind->iNum <= iIndex) return -1;
if(lpStreamInfo) {
pstr = &pfind->pstr[iIndex];
memset(lpStreamInfo, 0, sizeof(PSRSTREAMINFO));
lpStreamInfo->wTypeFlags = PSR_STRTYPE_AUDIO;
lpStreamInfo->wFormatTag = WAVE_FORMAT_PCM;
lpStreamInfo->wBitsPerSample = 16;
lpStreamInfo->nBeginSector = pstr->dwBegin;
lpStreamInfo->nNumSector =
(DWORD)pstr->usChannels * (pstr->nLength - 1) + 1;// 1.03
lpStreamInfo->wChannels = (pstr->bFlags & 0x01) ? 2 : 1;
lpStreamInfo->nSamplesPerSec = (pstr->bFlags & 0x04) ? 18900:37800;
lpStreamInfo->nPlayTime = (40320 * pstr->nLength) /
(lpStreamInfo->wChannels *
(lpStreamInfo->nSamplesPerSec / 100));
lpStreamInfo->nDataSize = pstr->nLength * 0x900; //1.30
}
return pfind->iNum;
}
/******************************************************************************/
/* */
/* PsrGetStrDataInfo() : ストリームデータ情報の取得 */
/* */
/******************************************************************************/
CEXPORT BOOL PsrGetStrDataInfo(
INT iDriveNo, // ドライブ番号
DWORD dwBegin, // 開始セクタ番号
DWORD dwNumSector, // セクタ数
LPPSRSTREAMINFO lpStreamInfo) // ストリームデータ情報
{
HANDLE hCdrom;
_PTSECTOR psector;
_TSUBHEADER subH;
DWORD nStep;
// CD-ROMのオープン ------------------------------------
hCdrom = CdReadOpen(iDriveNo, NULL, dwBegin, min(256, dwNumSector), -1);
if(!hCdrom) return FALSE;
// 最初のセクタを読み込む ------------------------------
if(!(psector = CdReadSector(hCdrom, NULL))) {
CdReadClose(hCdrom);
return FALSE;
}
subH = psector->asubH[0];
subH.bfType &= 0x7f;
CdUnlockReadBuffer(hCdrom, psector);
nStep = 1; // セクタ間隔を求める ----------------------------- 1.03
if(dwNumSector <= 1) {
while(1) {
if(!(psector = CdReadSector(hCdrom, NULL))) {
CdReadClose(hCdrom);
return FALSE;
}
if(subH.usChaNo == psector->asubH[0].usChaNo &&
subH.bfType == (psector->asubH[0].bfType & 0x7f) &&
subH.bfFlags == psector->asubH[0].bfFlags) {
break;
}
nStep ++;
CdUnlockReadBuffer(hCdrom, psector);
}
}
CdReadClose(hCdrom);
// ストリーム情報を設定する ----------------------------
memset(lpStreamInfo, 0, sizeof(PSRSTREAMINFO));
lpStreamInfo->wTypeFlags = PSR_STRTYPE_AUDIO;
lpStreamInfo->wFormatTag = WAVE_FORMAT_PCM;
lpStreamInfo->wBitsPerSample = 16;
lpStreamInfo->nBeginSector = dwBegin;
lpStreamInfo->nNumSector = dwNumSector;
lpStreamInfo->wChannels = (subH.bfFlags & 0x01) ? 2 : 1;
lpStreamInfo->nSamplesPerSec = (subH.bfFlags & 0x04) ? 18900 : 37800;
dwNumSector = (dwNumSector + (nStep - 1)) / nStep;
lpStreamInfo->nPlayTime = (40320 * dwNumSector) /
((DWORD)lpStreamInfo->wChannels *
(lpStreamInfo->nSamplesPerSec / 100));
return TRUE;
}
/******************************************************************************/
/* */
/* PsrOpenCD() : CDストリームのオープン */
/* */
/******************************************************************************/
CEXPORT HANDLE PsrOpenCD(
INT iDriveNo, // ドライブ番号
LPPSRSTREAMINFO lpStreamInfo) // ストリームデータ情報
{
_PTHANDLE phandle;
HANDLE hCdrom;
_PTSECTOR psector;
// CD-ROMのオープン ------------------------------------
hCdrom = CdReadOpen(iDriveNo, NULL,
lpStreamInfo->nBeginSector,
lpStreamInfo->nNumSector, -1);
if(!hCdrom) return NULL;
// ハンドルを作成 --------------------------------------
if(!(phandle = malloc(sizeof(_THANDLE)))) {
CdReadClose(hCdrom);
return NULL;
}
phandle->hCdrom = hCdrom;
phandle->nBegin = lpStreamInfo->nBeginSector;
phandle->nAllSector = lpStreamInfo->nNumSector;
phandle->nSamplingRate = lpStreamInfo->nSamplesPerSec;
phandle->wChannels = lpStreamInfo->wChannels;
phandle->wStep = 1; // 1.03
phandle->apSector[0] = NULL; // 1.03
phandle->apSector[1] = NULL; // 1.03
// セクタの間隔を求める --------------------------------
if(!(phandle->apSector[0] = CdReadSector(hCdrom, NULL))) {
free(phandle);
CdReadClose(hCdrom);
return NULL;
}
phandle->subH = phandle->apSector[0]->asubH[0];
phandle->subH.bfType &= 0x7f;
while(lpStreamInfo->nNumSector > 1) { // 1.03
if(!(psector = CdReadSector(hCdrom, NULL))) {
free(phandle);
CdReadClose(hCdrom);
return NULL;
}
if(phandle->subH.usChaNo == psector->asubH[0].usChaNo &&
phandle->subH.bfType == (psector->asubH[0].bfType & 0x7f) &&
phandle->subH.bfFlags == psector->asubH[0].bfFlags) {
phandle->apSector[1] = psector;
break;
}
phandle->wStep ++; // 1.03
}
return phandle;
}
/******************************************************************************/
/* */
/* PsrClose() : ストリームデータのクローズ */
/* */
/******************************************************************************/
CEXPORT BOOL PsrClose(
HANDLE hStream) // ストリームハンドル
{
_PTHANDLE phandle;
phandle = hStream;
if(phandle->hCdrom) CdReadClose(phandle->hCdrom);
free(phandle);
return TRUE;
}
/******************************************************************************/
/* */
/* PsrRead() : ストリームデータの読み取り */
/* */
/******************************************************************************/
CEXPORT BOOL PsrRead(
HANDLE hStream, // ストリームハンドル
LPPSRREADBUFF lpBuffer) // 読み取りバッファ
{
_PTHANDLE phandle;
_PTSECTOR psector;
phandle = hStream;
memset(lpBuffer, 0, sizeof(PSRREADBUFF) - PSR_FRAMEBUFFER);
if(phandle->apSector[0]) {
psector = phandle->apSector[0];
phandle->apSector[0] = NULL;
} else if(phandle->apSector[1]) {
psector = phandle->apSector[1];
phandle->apSector[1] = NULL;
} else {
psector = NULL;
}
if(psector) {
lpBuffer->nLength = 0x900;
memcpy(lpBuffer->abData, psector->abAudio, 0x900);
CdUnlockReadBuffer(phandle->hCdrom, psector);
return TRUE;
}
while(1) {
psector = CdReadSector(phandle->hCdrom, NULL);
if(!psector) return FALSE;
if(phandle->subH.usChaNo == psector->asubH[0].usChaNo &&
phandle->subH.bfType == (psector->asubH[0].bfType & 0x7f) &&
phandle->subH.bfFlags == psector->asubH[0].bfFlags) {
lpBuffer->nLength = 0x900;
memcpy(lpBuffer->abData, psector->abAudio, 0x900);
}
CdUnlockReadBuffer(phandle->hCdrom, psector);
if(lpBuffer->nLength) break;
}
return TRUE;
}
/******************************************************************************/
/* */
/* PsrSeek() : 読み取り位置の設定 */
/* */
/******************************************************************************/
CEXPORT BOOL PsrSeek(
HANDLE hStream, // ストリームハンドル
DWORD dwPosition) // 読み取り位置 1/1000秒単位
{
_PTHANDLE phandle;
DWORD dwSector;
phandle = hStream;
if(phandle->apSector[0]) {
CdUnlockReadBuffer(phandle->hCdrom, phandle->apSector[0]);
phandle->apSector[0] = NULL;
}
if(phandle->apSector[1]) {
CdUnlockReadBuffer(phandle->hCdrom, phandle->apSector[1]);
phandle->apSector[1] = NULL;
}
dwSector = (phandle->nSamplingRate / 100) * (dwPosition / 10);
dwSector /= (4032 / (DWORD)phandle->wChannels);
dwSector *= (DWORD)phandle->wStep;
dwSector = min(dwSector, phandle->nAllSector);
if(CdSetReadPointer(phandle->hCdrom, (LONG)dwSector, FILE_BEGIN) == 0xffffffff) {
return FALSE;
}
return TRUE;
}