LONG APIENTRY CONVProc( PVOID pmmioStr, USHORT usMsg, LONG lParam1, LONG lParam2 ) { PCONVPROCINFO pInfo; // Converter I/O Procedure Info Block PMMIOINFO pmmioinfo; // I/O information block MMIOINFO mmioinfoSS; // I/O info block for Storage System PMMFORMATINFO pmmformatinfo; // formatinfo for this ioproc. PCONVHEADERINFO pconvHeaderInfo; // pointer to header struct for FFT files. PSZ pszFileName; // file name passed in from caller PSZ pszFormatString; // format string to return. PSZ pszData; CHAR szHeaderLength[2]; // storage for header length (USHORT) PCHAR pTemp; // temp pointer for use in Header manip. HFILE hFileHandle; // file handle created or passed in HMMIO hmmioSS; // handle for Storage System FOURCC fccStorageSystem; // SS I/O Proc FOURCC USHORT usReturnCode; // return code from mmioClose ULONG ulReturnCode; // return code from mmio API calls LONG lReturnCode; // return code from mmio API calls LONG lBytesCopied; // num of bytes of format string. LONG lBytesRead; // return from mmioRead LONG lBytesWritten; // return from mmioWrite LONG lHeaderLength; // storage for CONV header length input LONG lFilePosition; // return from mmioSeek LONG lSavedFilePosition; // saved LFP for the file. ULONG ulTempFlags; // temp flags for flags to be removed. /* * Initalize local file handle and Return Codes. */ hFileHandle = 0L; ulReturnCode = 0L; usReturnCode = 0; /* * Clear the error return before anything happens to insure valid results. */ if (pmmioStr) { pmmioinfo = (PMMIOINFO) pmmioStr; pInfo = (PCONVPROCINFO) &pmmioinfo->aulInfo; pmmioinfo->ulErrorRet = MMIO_SUCCESS; } else { pmmioinfo = NULL; pInfo = NULL; } /* * Route the MMIO message to the proper code handler. */ switch( usMsg ) { case MMIOM_OPEN: /* * Get the filename from parameter. Then create a File Format header * in memory since this message will use this structure. */ pszFileName = (CHAR *)lParam1; pconvHeaderInfo = (PCONVHEADERINFO)HhpAllocBuffer( sizeof(CONVHEADERINFO), 0); if (!pconvHeaderInfo) { return (MMIO_ERROR); } /* * If no Storage System I/O proc was determined from mmioOpen, * either determine the SS from the name (CREATE case) or * search I/O proc list for SS type. If the file is being created * and the storage system cannot be determined from the name, * default the storage system to DOS. */ if (!pmmioinfo->fccChildIOProc) { /* * Since no Storage system has been determined from mmioOpen, we * need to determine the Storage system from the filename. If * it cannot be determined from the name, since it's a create we * will default the storage system to DOS. */ if (pmmioinfo->ulFlags & MMIO_CREATE) { if (mmioDetermineSSIOProc( pszFileName, pmmioinfo, &fccStorageSystem, NULL )) { fccStorageSystem = FOURCC_DOS; } } else { /* * The file already exists, so we need to determine the storage * system by looping through all the SS I/O procs until the SS * is determined or it is not. If it is not then this file * cannot be opened, so return an error. */ if (mmioIdentifyStorageSystem( pszFileName, pmmioinfo, &fccStorageSystem )) { return (MMIO_ERROR); } } /* * Now we either have a SS, and if so assign it to the SS I/O * proc field of the pmmioinfo sent in, or we don't so return. */ if (!fccStorageSystem) { return (MMIO_ERROR); } else { pmmioinfo->fccChildIOProc = fccStorageSystem; } } /* * We have the Storage System FOURCC so open the SS. * To set up the mmioOpen call to the storage system : * * 1. Initialize the mmioinfo passed in for the Storage System. * 2. Set fccIOProc to the Storage System FOURCC. * 3. Save the hmmcf handle in aulInfo[1] if sent in. * 4. IMPORTANT: Use flags sent in EXCEPT Buffered I/O flags. * VERY IMPORTANT: Set the NOIDENTIFY flag before calling the * mmioOpen below to avoid and endless loop. * 5. The open call will handle the DELETE flag. * 6. Use the name passed in to this I/O proc for the open because * at this point the SS I/O proc will know how to deal with it. */ memset( &mmioinfoSS, '\0', sizeof(MMIOINFO)); mmioinfoSS.fccIOProc = pmmioinfo->fccChildIOProc; memmove( &mmioinfoSS.aulInfo, pmmioinfo->aulInfo,(4*sizeof(ULONG))); mmioinfoSS.ulFlags = pmmioinfo->ulFlags; ulTempFlags = (MMIO_CREATE|MMIO_READ|MMIO_WRITE|MMIO_READWRITE| MMIO_COMPAT|MMIO_EXCLUSIVE|MMIO_DENYWRITE| MMIO_DENYREAD|MMIO_DENYNONE|MMIO_DELETE|MMIO_VERTBAR| MMIO_APPEND|MMIO_USE_TEMP|MMIO_RWMODE|MMIO_SHAREMODE| MMIO_NOTRANSLATE|MMIO_TRANSLATEDATA| MMIO_TRANSLATEHEADER); mmioinfoSS.ulFlags &= ulTempFlags; mmioinfoSS.ulFlags |= MMIO_NOIDENTIFY; hmmioSS = mmioOpen( pszFileName, &mmioinfoSS, mmioinfoSS.ulFlags ); if (hmmioSS) { /* * Handle a DELETE request for the file format by returning * success if ( hmmio = TRUE = 1). */ if (pmmioinfo->ulFlags & MMIO_DELETE) { return (MMIO_SUCCESS); } pInfo->hmmioSS = hmmioSS; } else { return (mmioinfoSS.ulErrorRet); } /* * Get the header for the file if it already exists and * store it with the MMIOINFO for the file. */ if (!(pmmioinfo->ulFlags & MMIO_CREATE)) { /* * Seek the file to the beginning to read in the header. */ lFilePosition = mmioSeek( hmmioSS, 0L, SEEK_SET ); if (lFilePosition < 0L) { mmioClose( hmmioSS, 0L ); return (MMIO_ERROR); } /* * Read the header of the file into the provided buffer for the * given length. */ lBytesRead = mmioRead( hmmioSS, (PSZ)pconvHeaderInfo, sizeof(CONVHEADERINFO) ); if (lBytesRead < 0L) { mmioClose( hmmioSS, 0L ); return (MMIO_ERROR); } } else { /* * Make a new header for the file and write it to the beginning. */ pconvHeaderInfo->ulHeaderLength = sizeof(CONVHEADERINFO); strcpy( pconvHeaderInfo->szHeaderText, HEADER_STRING ); lFilePosition = mmioSeek( hmmioSS, 0L, SEEK_SET ); if (lFilePosition < 0L) { mmioClose( hmmioSS, 0L ); return (MMIO_ERROR); } /* * Write the newly created header to the file. */ lBytesWritten = mmioWrite( hmmioSS, (PSZ)pconvHeaderInfo, sizeof(CONVHEADERINFO) ); if (lBytesWritten < 0L) { mmioClose( hmmioSS, 0L ); return (MMIO_ERROR); } } pconvHeaderInfo->ulFlags = 0; pmmioinfo->pExtraInfoStruct = (PVOID)pconvHeaderInfo; /* * Seek the file past the header to allow reads/writes to occur * at the first byte of non-header data if the file already exists. */ lReturnCode = mmioSeek( hmmioSS, sizeof(CONVHEADERINFO), SEEK_SET ); if (lReturnCode >= 0L) { pmmioinfo->lLogicalFilePos = lReturnCode; } else { mmioClose( hmmioSS, 0L ); return (lReturnCode); } return (0L); break; case MMIOM_READ: /* * Call the read API with the Storage System handle using the * parameters that have been passed in to this I/O proc. */ lBytesRead = mmioRead( pInfo->hmmioSS, (CHAR *) lParam1, lParam2 ); /* * Check the return code and determine if read was successful. * Read must return: * -1 - an error occurred with mmioRead or somewhere internally. * x - number of bytes actually read by mmioRead. */ if ( lBytesRead < 0L ) { return( -1L ); } else { return( lBytesRead ); } break; case MMIOM_WRITE: /* * Call the write API with the Storage System handle using the * parameters that have been passed in to this I/O proc. */ lBytesWritten = mmioWrite( pInfo->hmmioSS, (CHAR *) lParam1, lParam2 ); /* * Check the return code and determine if write was successful. * Write must return: * -1 - an error occurred with mmioWrite or somewhere internally. * x - number of bytes actually written by mmioWrite. */ if ( lBytesWritten < 0L ) { return( -1L ); } else if ( lBytesWritten != lParam2 ) { pmmioinfo->ulErrorRet = MMIOERR_CANNOTWRITE; return( lBytesWritten ); } else { /* * Set the Flags field in the CONV header to show it was modified. */ pconvHeaderInfo = (PCONVHEADERINFO)pmmioinfo->pExtraInfoStruct; if (pconvHeaderInfo) pconvHeaderInfo->ulFlags = CONV_MODIFIED_FILE; return( lBytesWritten ); } break; case MMIOM_SEEK: /* * Call the seek API with the Storage System handle using the * parameters that have been passed in to this I/O proc. */ lReturnCode = mmioSeek( pInfo->hmmioSS, lParam1, lParam2 ); /* * Check the return code and determine if seek was successful. * Seek must return: * -1 - an error occurred with mmioSeek or somewhere internally. * x - new current file postion from the beginning of the file. */ if ( lReturnCode < 0L ) { return( -1L ); } return( lReturnCode ); break; case MMIOM_CLOSE: /* * If the CONV header structure was maintained in pExtraInfoStruct, * write it back to the beginning of the file. */ if (((pmmioinfo->ulFlags & MMIO_WRITE) || (pmmioinfo->ulFlags & MMIO_READWRITE)) && (pmmioinfo->pExtraInfoStruct)) { pconvHeaderInfo = (PCONVHEADERINFO)pmmioinfo->pExtraInfoStruct; lReturnCode = mmioSeek( pInfo->hmmioSS, 0L, SEEK_SET ); if (lReturnCode < 0L) { return (lReturnCode); } ulReturnCode = mmioSetHeader( pmmioinfo->hmmio, (PVOID)pmmioinfo->pExtraInfoStruct, sizeof(CONVHEADERINFO), &lBytesWritten, 0L, 0L ); if (ulReturnCode) { return (ulReturnCode); } } if (pmmioinfo->pExtraInfoStruct) HhpFreeBuffer((PBYTE)pmmioinfo->pExtraInfoStruct); /* * Call the close API with the Storage System handle using any * parameters that have been passed in to this I/O proc. */ usReturnCode = mmioClose( pInfo->hmmioSS, 0L ); return ((ULONG)usReturnCode); break; case MMIOM_IDENTIFYFILE: /* * Get the filename from parameter. Then create a File Format header * in memory since this message use this structure. */ pszFileName = (CHAR *)lParam1; // get the filename from parameter. pconvHeaderInfo = (PCONVHEADERINFO)HhpAllocBuffer( sizeof(CONVHEADERINFO), 0); if (!pconvHeaderInfo) { return (MMIO_ERROR); } hmmioSS = (HMMIO)lParam2; // get the SS handle to the file. if ( !hmmioSS ) { HhpFreeBuffer((PBYTE)pconvHeaderInfo); return (MMIO_ERROR); } else { /* * Seek the file to the beginning to read in the file header. */ lFilePosition = mmioSeek( hmmioSS, 0L, SEEK_SET ); if (lFilePosition < 0L) { HhpFreeBuffer((PBYTE)pconvHeaderInfo); return (MMIO_ERROR); } /* * Compare convHeaderInfo.szHeaderText with text string defined * in the convproc.h header file. */ lBytesRead = mmioRead( hmmioSS, (PSZ)pconvHeaderInfo, sizeof(CONVHEADERINFO) ); if ( lBytesRead <= 0L ) { HhpFreeBuffer((PBYTE)pconvHeaderInfo); return( -1L ); } pTemp = (CHAR *)pconvHeaderInfo; pTemp += 2 * sizeof(ULONG); if (!strncmp( pTemp, HEADER_STRING, strlen(HEADER_STRING) )) { HhpFreeBuffer((PBYTE)pconvHeaderInfo); return( 0L ); } else { HhpFreeBuffer((PBYTE)pconvHeaderInfo); return( -1L ); } } break; case MMIOM_GETFORMATINFO: /* * Fill in the mmformatinfo for the CONVProc. */ pmmformatinfo = (PMMFORMATINFO)lParam1; if (pmmformatinfo == NULL) { return( -1L ); } pmmformatinfo->ulStructLen = sizeof(MMFORMATINFO); pmmformatinfo->fccIOProc = FOURCC_FFT; pmmformatinfo->ulIOProcType = MMIO_IOPROC_FILEFORMAT; pmmformatinfo->ulMediaType = MMIO_MEDIATYPE_OTHER; pmmformatinfo->ulFlags = MMIO_CANREADUNTRANSLATED | MMIO_CANWRITEUNTRANSLATED | MMIO_CANREADWRITEUNTRANSLATED | MMIO_CANSEEKUNTRANSLATED; memset( pmmformatinfo->szDefaultFormatExt, '\0', sizeof(pmmformatinfo->szDefaultFormatExt) ); strcpy( pmmformatinfo->szDefaultFormatExt, "FFT" ); if (convhlpGetNLSData( &pmmformatinfo->ulCodePage, &pmmformatinfo->ulLanguage )) { return( -1L ); } if (convhlpGetFormatStringLength( FOURCC_FFT, &(pmmformatinfo->lNameLength) )) { return( -1L ); } return( 0L ); break; case MMIOM_GETFORMATNAME: /* * The string is in a resource file (CONVPROC.RC) for NLS purposes. */ pszFormatString = (CHAR *)lParam1; lBytesCopied = convhlpGetFormatString( FOURCC_FFT, pszFormatString, lParam2 ); return( lBytesCopied ); break; case MMIOM_QUERYHEADERLENGTH: /* * Save current file position for later restore. Then * seek the file to the beginning to read in the header. */ lSavedFilePosition = pmmioinfo->lLogicalFilePos; lFilePosition = mmioSeek( pInfo->hmmioSS, 0L, SEEK_SET ); if (lFilePosition < 0L) { return (0L); } /* * Read in the header length for the file. It is the first 4 bytes. */ lBytesRead = mmioRead( pInfo->hmmioSS, szHeaderLength, sizeof(ULONG) ); lReturnCode = mmioSeek( pInfo->hmmioSS, lSavedFilePosition, SEEK_SET ); if (lReturnCode != lSavedFilePosition) { return (0L); } if (lBytesRead <= 0L) { return (0L); } else { lHeaderLength = (LONG)(*((LONG *)szHeaderLength)); return (lHeaderLength); } break; case MMIOM_GETHEADER: /* * Save current file position for later restore. Then * seek the file to the beginning to read in the header. */ lSavedFilePosition = pmmioinfo->lLogicalFilePos; lFilePosition = mmioSeek( pInfo->hmmioSS, 0L, SEEK_SET ); if (lFilePosition < 0L) { return (0L); } /* * Read the header of the file into the provided buffer for the * given length. Then seek the file back to the saved position. */ lBytesRead = mmioRead( pInfo->hmmioSS, (CHAR *)lParam1, lParam2 ); lReturnCode = mmioSeek( pInfo->hmmioSS, lSavedFilePosition, SEEK_SET ); if (lReturnCode != lSavedFilePosition) { return (0L); } if (lBytesRead <= 0L) { return (0L); } else { return (lBytesRead); } break; case MMIOM_SETHEADER: /* * Save current file position for later restore. Then * seek the file to the beginning to read in the header. */ lSavedFilePosition = pmmioinfo->lLogicalFilePos; lFilePosition = mmioSeek( pInfo->hmmioSS, 0L, SEEK_SET ); if (lFilePosition < 0L) { return (0L); } /* * Write the entire header to the file. Then seek the file back * to the saved file position. */ lBytesWritten = mmioWrite( pInfo->hmmioSS, (CHAR *)lParam1, lParam2 ); lReturnCode = mmioSeek( pInfo->hmmioSS, lSavedFilePosition, SEEK_SET ); if (lReturnCode != lSavedFilePosition) { return (0L); } if (lBytesWritten <= 0L) { return (0L); } else { return (lBytesWritten); } break; case CONVM_TOUPPER: pszData = (CHAR *)lParam1; convhlpToUpper( (PUCHAR)pszData ); return (MMIO_SUCCESS); break; case CONVM_TOLOWER: pszData = (CHAR *)lParam1; convhlpToLower( (PUCHAR)pszData ); return (MMIO_SUCCESS); break; default: /* * If an IO Proc has a child IO Proc, then instead of * returning UNSUPPORTED_MESSAGE, send the message to * the child IO Proc to see if it can understand and * process the message. * * Since message is unexpected, need to check for valid * pointers. */ if (pInfo) { if (pInfo->hmmioSS) { lReturnCode = ( mmioSendMessage( pInfo->hmmioSS, usMsg, lParam1, lParam2 )); if (!lReturnCode) pmmioinfo->ulErrorRet = mmioGetLastError(pInfo->hmmioSS); return (lReturnCode); } } else { if (pmmioinfo) pmmioinfo->ulErrorRet = MMIOERR_UNSUPPORTED_MESSAGE; } return (MMIOERR_UNSUPPORTED_MESSAGE); } }
static LONG APIENTRY IOProc_Entry2(PVOID pmmioStr, USHORT usMsg, LONG lParam1, LONG lParam2) { PMMIOINFO pmmioinfo = (PMMIOINFO)pmmioStr; switch (usMsg) { case MMIOM_OPEN: { HMMIO hmmioSS; MMIOINFO mmioinfoSS; PSZ pszFileName = (char *)lParam1; if (!pmmioinfo) return MMIO_ERROR; if ((pmmioinfo->ulFlags & MMIO_READWRITE)) { #ifdef DEBUG fprintf(file,"ReadWrite - requested.\n"); #endif return MMIO_ERROR; } if (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA)) return MMIO_ERROR; if (!pmmioinfo->fccChildIOProc) { FOURCC fccFileStorageSystem; if (pmmioinfo->ulFlags & MMIO_CREATE) { if (mmioDetermineSSIOProc(pszFileName, pmmioinfo, &fccFileStorageSystem, NULL)) { fccFileStorageSystem = FOURCC_DOS; } } else { if (mmioIdentifyStorageSystem(pszFileName, pmmioinfo, &fccFileStorageSystem)) { return MMIO_ERROR; } } if (!fccFileStorageSystem) { return MMIO_ERROR; } else { pmmioinfo->fccChildIOProc = fccFileStorageSystem; } /* endif */ } memmove(&mmioinfoSS, pmmioinfo, sizeof(MMIOINFO)); mmioinfoSS.pIOProc = NULL; mmioinfoSS.fccIOProc = pmmioinfo->fccChildIOProc; mmioinfoSS.ulFlags |= MMIO_NOIDENTIFY; hmmioSS = mmioOpen (pszFileName, &mmioinfoSS, mmioinfoSS.ulFlags); if (pmmioinfo->ulFlags & MMIO_DELETE) { if (!hmmioSS) { pmmioinfo->ulErrorRet = MMIOERR_DELETE_FAILED; return MMIO_ERROR; } else return MMIO_SUCCESS; } if (!hmmioSS) return MMIO_ERROR; if (pmmioinfo->ulFlags & MMIO_READ) { DecInfo *decInfo = (DecInfo *)malloc(sizeof(DecInfo)); #ifdef DEBUG fprintf(file,"File Read: %s\n",pszFileName); #endif if (!decInfo) { mmioClose(hmmioSS, 0); return MMIO_ERROR; } decInfo->t = READNUM; decInfo->vorbisOptions = pmmioinfo->pExtraInfoStruct; pmmioinfo->pExtraInfoStruct = (PVOID)decInfo; { ov_callbacks cb; cb.read_func = mread; cb.seek_func = mseek; cb.close_func = mclose; cb.tell_func = mtell; if(0 != ov_open_callbacks((void *)hmmioSS, &decInfo->oggfile, 0, 0, cb)) { free(decInfo); mmioClose(hmmioSS, 0); return MMIO_ERROR; } } #ifdef DEBUG fprintf(file,"Open successfull\n"); #endif return MMIO_SUCCESS; } else if (pmmioinfo->ulFlags & MMIO_WRITE) { EncInfo *encInfo = (EncInfo *)malloc(sizeof(EncInfo)); #ifdef DEBUG fprintf(file,"File Write: %s\n",pszFileName); #endif if (!encInfo) { mmioClose(hmmioSS, 0); return MMIO_ERROR; } memset(encInfo, 0, sizeof(EncInfo)); encInfo->t = WRITENUM; encInfo->hmmioSS = hmmioSS; encInfo->vorbisOptions = (PVORBISOPTIONS)pmmioinfo->pExtraInfoStruct; pmmioinfo->pExtraInfoStruct = (PVOID)encInfo; return MMIO_SUCCESS; } #ifdef DEBUG fprintf(file,"File not read nor write: %s\n",pszFileName); #endif return MMIO_ERROR; } break; case MMIOM_READ: { if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct || !lParam1) return MMIO_ERROR; if (!pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA) { return MMIO_ERROR; // return mmioRead (ogginfo->hmmioSS, (PVOID) lParam1, (ULONG) lParam2); } else { OggVorbis_File *oggfile; long rc = 0; int current_section; long total = 0; oggfile = &((DecInfo *)pmmioinfo->pExtraInfoStruct)->oggfile; if (READNUM != ((DecInfo *)pmmioinfo->pExtraInfoStruct)->t) return MMIO_ERROR; while (lParam2 > 0) { rc = ov_read(oggfile, (char *)lParam1, (int)lParam2, 0, 2, 1, ¤t_section); if (rc < 0) { #ifdef DEBUG fprintf(file, "Read failed once\n"); #endif continue; } if (rc <= 0) break; lParam2 -= rc; lParam1 += rc; total += rc; } #ifdef DEBUG fprintf(file,"Read rc:%ld total:%ld\n",rc,total); #endif if (rc < 0) return MMIO_ERROR; return total; } } break; case MMIOM_SEEK: { LONG lPosDesired; OggVorbis_File *oggfile; vorbis_info *vi; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return MMIO_ERROR; if (!pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA) return MMIO_ERROR; oggfile = &((DecInfo *)pmmioinfo->pExtraInfoStruct)->oggfile; if (READNUM != ((DecInfo *)pmmioinfo->pExtraInfoStruct)->t) return MMIO_ERROR; vi = ov_info(oggfile, -1); if (!vi) return MMIO_ERROR; if (SEEK_SET == lParam2) { lPosDesired = lParam1/(2*vi->channels); } else if (SEEK_CUR == lParam2) { if (0 == lParam1) { return ov_pcm_tell(oggfile)*2*vi->channels; } /* endif */ lPosDesired = ov_pcm_tell(oggfile) + lParam1/(2*vi->channels); } else if (SEEK_END == lParam2) { lPosDesired = ov_pcm_total(oggfile,-1) + lParam1/(2*vi->channels); } else { return MMIO_ERROR; } #ifdef DEBUG fprintf(file,"Seek to %ld by %d\n",lPosDesired, lParam2); #endif if (ov_pcm_seek(oggfile, lPosDesired) < 0) return MMIO_ERROR; return lPosDesired*2*vi->channels; } break; case MMIOM_CLOSE: { int rc; #ifdef DEBUG fprintf(file,"start CLOSE\n"); #endif if (!pmmioinfo) return MMIO_ERROR; if (pmmioinfo->pExtraInfoStruct) { DecInfo *decInfo = (DecInfo *)pmmioinfo->pExtraInfoStruct; #ifdef DEBUG fprintf(file,"ready CLOSE\n"); #endif if (READNUM == decInfo->t) { #ifdef DEBUG fprintf(file,"read CLOSE\n"); #endif ov_clear(&decInfo->oggfile); free(decInfo); decInfo = 0; rc=MMIO_SUCCESS; } else if (WRITENUM == decInfo->t) { EncInfo *encInfo = (EncInfo*)pmmioinfo->pExtraInfoStruct; #ifdef DEBUG fprintf(file,"write CLOSE\n"); #endif if (encInfo->headerSet) { vorbis_analysis_wrote(&encInfo->vd,0); rc = oggWrite(encInfo,1); ogg_stream_clear(&encInfo->os); vorbis_block_clear(&encInfo->vb); vorbis_dsp_clear(&encInfo->vd); vorbis_comment_clear(&encInfo->vc); vorbis_info_clear(&encInfo->vi); } mmioClose(encInfo->hmmioSS, 0); free(encInfo); encInfo = 0; rc = MMIO_SUCCESS; } else rc = MMIO_ERROR; pmmioinfo->pExtraInfoStruct = 0; #ifdef DEBUG fprintf(file,"CLOSE\n"); #endif return rc; } return MMIO_ERROR; } break; case MMIOM_IDENTIFYFILE: { unsigned char buf[4]; HMMIO hmmioTemp; ULONG ulTempFlags = MMIO_READ | MMIO_DENYWRITE | MMIO_NOIDENTIFY; LONG rc = MMIO_ERROR; if (!lParam1 && !lParam2) return MMIO_ERROR; hmmioTemp = (HMMIO)lParam2; if (!hmmioTemp) { hmmioTemp = mmioOpen((PSZ)lParam1, NULL, ulTempFlags); } if (hmmioTemp) { rc = mmioRead(hmmioTemp, buf, 4); if (rc == 4 && buf[0] == 'O' && buf[1] == 'g' && buf[2] == 'g' && buf[3] == 'S') { rc = MMIO_SUCCESS; } if (!lParam2) mmioClose(hmmioTemp, 0); } return rc; } break; case MMIOM_GETFORMATINFO: { PMMFORMATINFO pmmformatinfo; pmmformatinfo = (PMMFORMATINFO)lParam1; pmmformatinfo->ulStructLen = sizeof(MMFORMATINFO); pmmformatinfo->fccIOProc = FOURCC_Vorbis; pmmformatinfo->ulIOProcType = MMIO_IOPROC_FILEFORMAT; pmmformatinfo->ulMediaType = MMIO_MEDIATYPE_AUDIO; pmmformatinfo->ulFlags = MMIO_CANREADTRANSLATED | MMIO_CANWRITETRANSLATED | MMIO_CANSEEKTRANSLATED; strcpy(pmmformatinfo->szDefaultFormatExt, "OGG"); pmmformatinfo->ulCodePage = 0; pmmformatinfo->ulLanguage = 0; pmmformatinfo->lNameLength = 21; return MMIO_SUCCESS; } break; case MMIOM_GETFORMATNAME: if (lParam2 > 21) { strcpy((PSZ)lParam1, "Ogg Vorbis"); return MMIO_SUCCESS; } else return MMIO_ERROR; break; case MMIOM_QUERYHEADERLENGTH: return (sizeof (MMAUDIOHEADER)); break; case MMIOM_GETHEADER: { OggVorbis_File *oggfile; DecInfo *decInfo; PMMAUDIOHEADER mmaudioheader; vorbis_info *vi; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return 0; if (!(pmmioinfo->ulFlags & MMIO_READ)) return 0; decInfo = (DecInfo *)pmmioinfo->pExtraInfoStruct; oggfile = &decInfo->oggfile; if (READNUM != decInfo->t){ pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE; return 0; } #ifdef DEBUG fprintf(file,"HERE\n"); #endif if (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA)) return 0; mmaudioheader = (MMAUDIOHEADER *)lParam1; if (sizeof(MMAUDIOHEADER) > lParam2) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_BUFFER_LENGTH; return 0; } #ifdef DEBUG fprintf(file,"THERE\n"); #endif vi = ov_info(oggfile, -1); if (!vi) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE; return 0; } mmaudioheader->ulContentType = MMIO_MIDI_UNKNOWN; mmaudioheader->ulMediaType = MMIO_MEDIATYPE_AUDIO; mmaudioheader->mmXWAVHeader.WAVEHeader.usFormatTag=DATATYPE_WAVEFORM; mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels = vi->channels; mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec = vi->rate; mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample = 16; mmaudioheader->mmXWAVHeader.WAVEHeader.ulAvgBytesPerSec= mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels * mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec * mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample / 8; mmaudioheader->mmXWAVHeader.WAVEHeader.usBlockAlign= mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels * mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample / 8; mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInMS= (unsigned long)(ov_time_total(oggfile, -1)*1000.0); mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes= (unsigned long)ov_pcm_total(oggfile, -1)* mmaudioheader->mmXWAVHeader.WAVEHeader.usBlockAlign; #ifdef DEBUG fprintf(file,"time: %ld size: %ld rate: %ld\n", mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInMS, mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec); #endif if (0 != decInfo->vorbisOptions && VORBIS_COOKIE == decInfo->vorbisOptions->cookie) { decInfo->vorbisOptions->nominal_bitrate = ov_bitrate(oggfile, -1); mmaudioheader->mmXWAVHeader.XWAVHeaderInfo.pAdditionalInformation = decInfo->vorbisOptions; } return (sizeof (MMAUDIOHEADER)); } break; case MMIOM_SETHEADER: { EncInfo *encInfo; PMMAUDIOHEADER mmaudioheader; int totalout = 0; int rc; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return 0; encInfo = (EncInfo*)pmmioinfo->pExtraInfoStruct; if (WRITENUM != encInfo->t) return 0; #ifdef DEBUG fprintf(file,"write header: %x, %x, %x\n",!(pmmioinfo->ulFlags & MMIO_WRITE), encInfo->headerSet, (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA))); fprintf(file,"flag: %x, trans: %x\n",pmmioinfo->ulFlags,pmmioinfo->ulTranslate); #endif if (/*!(pmmioinfo->ulFlags & MMIO_WRITE) ||*/ encInfo->headerSet || (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEHEADER) && !(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA))) return 0; if (!lParam1) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_STRUCTURE; return 0; } mmaudioheader = (PMMAUDIOHEADER)lParam1; if (lParam2 != sizeof(MMAUDIOHEADER)) { pmmioinfo->ulErrorRet = MMIOERR_INVALID_BUFFER_LENGTH; return 0; } /********** Encode setup ************/ if (0 != mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample%8) { /* Bit-rate must be multiple of 8 */ return 0; } encInfo->bitsPerSample=mmaudioheader->mmXWAVHeader.WAVEHeader.usBitsPerSample; #ifdef DEBUG fprintf(file,"ready to write header: "); #endif vorbis_info_init(&encInfo->vi); if (0 == encInfo->vorbisOptions || VORBIS_COOKIE != encInfo->vorbisOptions->cookie) { #ifdef DEBUG fprintf(file,"default quality 0.3\n"); #endif rc = vorbis_encode_init_vbr(&encInfo->vi, mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec, 0.3); } else { #ifdef DEBUG fprintf(file,"bitsPerSample: %d channels: %d samplesPerSec: %ld min: %ld nominal: %ld max: %ld\n", encInfo->bitsPerSample, mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec, encInfo->vorbisOptions->max_bitrate, encInfo->vorbisOptions->nominal_bitrate, encInfo->vorbisOptions->min_bitrate); #endif rc = vorbis_encode_init(&encInfo->vi, mmaudioheader->mmXWAVHeader.WAVEHeader.usChannels, mmaudioheader->mmXWAVHeader.WAVEHeader.ulSamplesPerSec, encInfo->vorbisOptions->max_bitrate, encInfo->vorbisOptions->nominal_bitrate, encInfo->vorbisOptions->min_bitrate); } if (rc) { #ifdef DEBUG fprintf(file,"encodeInit failed: %d\n",rc); #endif return 0; } /* endif */ /* add a comment */ vorbis_comment_init(&encInfo->vc); vorbis_comment_add_tag(&encInfo->vc,"ENCODER","mmioVorbis"); /* set up the analysis state and auxiliary encoding storage */ vorbis_analysis_init(&encInfo->vd,&encInfo->vi); vorbis_block_init(&encInfo->vd,&encInfo->vb); /* set up our packet->stream encoder */ /* pick a random serial number; that way we can more likely build chained streams just by concatenation */ srand(time(NULL)); ogg_stream_init(&encInfo->os,rand()); { ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&encInfo->vd,&encInfo->vc,&header,&header_comm,&header_code); ogg_stream_packetin(&encInfo->os,&header); /* automatically placed in its own page */ ogg_stream_packetin(&encInfo->os,&header_comm); ogg_stream_packetin(&encInfo->os,&header_code); while(1){ int result=ogg_stream_flush(&encInfo->os,&encInfo->og); if(result==0)break; result = mmioWrite(encInfo->hmmioSS, encInfo->og.header,encInfo->og.header_len); totalout += result; if (result!=encInfo->og.header_len) { ogg_stream_clear(&encInfo->os); vorbis_block_clear(&encInfo->vb); vorbis_dsp_clear(&encInfo->vd); vorbis_comment_clear(&encInfo->vc); vorbis_info_clear(&encInfo->vi); return 0; } result = mmioWrite(encInfo->hmmioSS, encInfo->og.body,encInfo->og.body_len); totalout += result; if (result!=encInfo->og.body_len) { ogg_stream_clear(&encInfo->os); vorbis_block_clear(&encInfo->vb); vorbis_dsp_clear(&encInfo->vd); vorbis_comment_clear(&encInfo->vc); vorbis_info_clear(&encInfo->vi); return 0; } } } encInfo->headerSet = 1; return totalout; } break; case MMIOM_WRITE: { EncInfo *encInfo; if (!pmmioinfo || !pmmioinfo->pExtraInfoStruct) return MMIO_ERROR; encInfo = (EncInfo*)pmmioinfo->pExtraInfoStruct; if (WRITENUM != encInfo->t) return MMIO_ERROR; if (!encInfo->headerSet) return MMIO_ERROR; if (!(pmmioinfo->ulTranslate & MMIO_TRANSLATEDATA)) { if (!lParam1) return MMIO_ERROR; return mmioWrite(encInfo->hmmioSS, (PVOID)lParam1, lParam2); } else { if (lParam2 == 0) { vorbis_analysis_wrote(&encInfo->vd,0); } else { long i; int j, k; int num; float denom = 1; signed char *readbuffer = (char *)lParam1; /* data to encode */ /* expose the buffer to submit data */ int sampleSize = encInfo->vi.channels*encInfo->bitsPerSample/8; int samples = lParam2/sampleSize; float **buffer=vorbis_analysis_buffer(&encInfo->vd, samples); #ifdef DEBUG fprintf(file,"write: %ld\n",lParam2); #endif /* :TODO: Work with buffers not a multiple of sampleSize*/ if (lParam2 % sampleSize != 0) { #ifdef DEBUG fprintf(file,"Bad Write Buffer Size\n"); #endif return MMIO_ERROR; } for(i=0;i<samples;i++){ for (j=0;j<encInfo->vi.channels;j++) { num=0; denom=0.5; if (encInfo->bitsPerSample<=8) { buffer[j][i]=(float)((unsigned char)(readbuffer[i*sampleSize])- (1<<(encInfo->bitsPerSample-1)))/ (float)(1<<(encInfo->bitsPerSample-1)); } else { for (k=encInfo->bitsPerSample/8;k>0;k--) { if (k==encInfo->bitsPerSample/8) { num=(readbuffer[i*sampleSize+k-1]); } else { num=(num<<8)|((0xff)&(int)(readbuffer[i*sampleSize+k-1])); } denom *= 256.0; } buffer[j][i]=((float)num)/denom; } } /* endfor */ } vorbis_analysis_wrote(&encInfo->vd,i); } /* endif */ if (oggWrite(encInfo,0)>=0) { return lParam2; } else { return MMIO_ERROR; } /* endif */ } } break; #ifdef DEBUG case MMIOM_TEMPCHANGE: { return MMIO_SUCCESS; } break; #endif } #ifdef DEBUG fprintf(file,"unexpected command: %x\n",usMsg); #endif return MMIOERR_UNSUPPORTED_MESSAGE; }