int main(int argc, char* argv[]) { // LPWSTR szFileName;//声音文件名 MMCKINFO mmckinfoParent; MMCKINFO mmckinfoSubChunk; DWORD dwFmtSize; HMMIO m_hmmio;//音频文件句柄 DWORD m_WaveLong; HPSTR lpData;//音频数据 HANDLE m_hData=NULL; HANDLE m_hFormat; WAVEFORMATEX * lpFormat; DWORD m_dwDataOffset; DWORD m_dwDataSize; WAVEHDR pWaveOutHdr; WAVEOUTCAPS pwoc; HWAVEOUT hWaveOut; int SoundOffset=0; int SoundLong=0; int DevsNum; //打开波形文件 if(!(m_hmmio=mmioOpen(argv[1],NULL,MMIO_READ|MMIO_ALLOCBUF))) { //File open Error printf("Failed to open the file.");//错误处理函数 return false; } //检查打开文件是否是声音文件 mmckinfoParent.fccType =mmioFOURCC('W','A','V','E'); if(mmioDescend(m_hmmio,(LPMMCKINFO)&mmckinfoParent,NULL,MMIO_FINDRIFF)) { printf("NOT WAVE FILE AND QUIT"); return 0; } //寻找 'fmt' 块 mmckinfoSubChunk.ckid =mmioFOURCC('f','m','t',' '); if(mmioDescend(m_hmmio,&mmckinfoSubChunk,&mmckinfoParent,MMIO_FINDCHUNK)) { printf("Can't find 'fmt' chunk"); return 0; } //获得 'fmt '块的大小,申请内存 dwFmtSize=mmckinfoSubChunk.cksize ; m_hFormat=LocalAlloc(LMEM_MOVEABLE,LOWORD(dwFmtSize)); if(!m_hFormat) { printf("failed alloc memory"); return 0; } lpFormat=(WAVEFORMATEX*)LocalLock(m_hFormat); if(!lpFormat) { printf("failed to lock the memory"); return 0; } if((unsigned long)mmioRead(m_hmmio,(HPSTR)lpFormat,dwFmtSize)!=dwFmtSize) { printf("failed to read format chunk"); return 0; } //离开 fmt 块 mmioAscend(m_hmmio,&mmckinfoSubChunk,0); //寻找 'data' 块 mmckinfoSubChunk.ckid=mmioFOURCC('d','a','t','a'); if(mmioDescend(m_hmmio,&mmckinfoSubChunk,&mmckinfoParent,MMIO_FINDCHUNK)) { printf("Can't find 'data' chunk"); return 0; } //获得 'data'块的大小 m_dwDataSize=mmckinfoSubChunk.cksize ; m_dwDataOffset =mmckinfoSubChunk.dwDataOffset ; if(m_dwDataSize==0L) { printf("no data in the 'data' chunk"); return 0; } //为音频数据分配内存 lpData=new char[m_dwDataSize]; if(!lpData) { printf("\ncan not alloc mem"); return 0; } if(mmioSeek(m_hmmio,m_dwDataOffset,SEEK_SET)<0) { printf("Failed to read the data chunk"); return 0; } // m_WaveLong=mmioRead(m_hmmio,lpData,SoundLong); m_WaveLong=mmioRead(m_hmmio,lpData,m_dwDataSize); if(m_WaveLong<0) { printf("Failed to read the data chunk"); return 0; } //检查音频设备,返回音频输出设备的性能 if(waveOutGetDevCaps(WAVE_MAPPER,&pwoc,sizeof(WAVEOUTCAPS))!=0) { printf("Unable to allocate or lock memory"); return 0; } //检查音频输出设备是否能播放指定的音频文件 DevsNum = WAVE_MAPPER; if(waveOutOpen(&hWaveOut,DevsNum,lpFormat,NULL,NULL,CALLBACK_NULL)!=0) { printf("Failed to OPEN the wave out devices"); // return 0; } //准备待播放的数据 pWaveOutHdr.lpData =(HPSTR)lpData; pWaveOutHdr.dwBufferLength =m_WaveLong; pWaveOutHdr.dwFlags =0; pWaveOutHdr.dwLoops = 10; if(waveOutPrepareHeader(hWaveOut,&pWaveOutHdr,sizeof(WAVEHDR))!=0) { printf("Failed to prepare the wave data buffer"); return 0; } printFlags(pWaveOutHdr.dwFlags, "after [waveOutPrepareHeader]"); pWaveOutHdr.dwFlags |= (WHDR_BEGINLOOP | WHDR_ENDLOOP); //播放音频数据文件 if(waveOutWrite(hWaveOut,&pWaveOutHdr,sizeof(WAVEHDR))!=0) { printf("Failed to write the wave data buffer"); return 0; } printFlags(pWaveOutHdr.dwFlags, "after [waveOutWrite]"); //关闭音频输出设备,释放内存 // printf("\npress any key"); // getchar(); Sleep(20000); printFlags(pWaveOutHdr.dwFlags, "after [Sleep]"); if(waveOutUnprepareHeader(hWaveOut, &pWaveOutHdr, sizeof(pWaveOutHdr)) != 0) { printf("Failed to unPrepare the wave data buffer"); return 0; } printFlags(pWaveOutHdr.dwFlags, "after [waveOutUnprepareHeader]"); waveOutReset(hWaveOut); printFlags(pWaveOutHdr.dwFlags, "after [waveOutReset]"); waveOutClose(hWaveOut); printFlags(pWaveOutHdr.dwFlags, "after [waveOutClose]"); LocalUnlock(m_hFormat); LocalFree(m_hFormat); delete [] lpData; return 0; }
// Open BOOL WaveFile::Open (LPSTR pszFilename) { int done = FALSE; WORD cbExtra = 0; BOOL fRtn = SUCCESS; // assume success PCMWAVEFORMAT pcmwf; char fullpath[_MAX_PATH]; m_total_uncompressed_bytes_read = 0; m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX; int FileSize, FileOffset; if ( !cf_find_file_location(pszFilename, CF_TYPE_ANY, fullpath, &FileSize, &FileOffset )) { goto OPEN_ERROR; } cfp = mmioOpen(fullpath, NULL, MMIO_ALLOCBUF | MMIO_READ); if ( cfp == NULL ) { goto OPEN_ERROR; } // Skip the "RIFF" tag and file size (8 bytes) // Skip the "WAVE" tag (4 bytes) mmioSeek( cfp, 12+FileOffset, SEEK_SET ); // Now read RIFF tags until the end of file uint tag, size, next_chunk; while(done == FALSE) { if ( mmioRead(cfp, (char *)&tag, sizeof(uint)) != sizeof(uint) ) break; if ( mmioRead(cfp, (char *)&size, sizeof(uint)) != sizeof(uint) ) break; next_chunk = mmioSeek( cfp, 0, SEEK_CUR ); next_chunk += size; switch( tag ) { case 0x20746d66: // The 'fmt ' tag mmioRead( cfp, (char *)&pcmwf, sizeof(PCMWAVEFORMAT) ); if ( pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM ) { mmioRead( cfp, (char *)&cbExtra, sizeof(short) ); } // Allocate memory for WAVEFORMATEX structure + extra bytes if ( (m_pwfmt_original = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX)+cbExtra )) != NULL ){ Assert(m_pwfmt_original != NULL); // Copy bytes from temporary format structure memcpy (m_pwfmt_original, &pcmwf, sizeof(pcmwf)); m_pwfmt_original->cbSize = cbExtra; // Read those extra bytes, append to WAVEFORMATEX structure if (cbExtra != 0) { mmioRead( cfp, (char *)((ubyte *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), cbExtra ); } } else { Int3(); // malloc failed goto OPEN_ERROR; } break; case 0x61746164: // the 'data' tag m_nDataSize = size; // This is size of data chunk. Compressed if ADPCM. m_data_bytes_left = size; m_data_offset = mmioSeek( cfp, 0, SEEK_CUR); done = TRUE; break; default: // unknown, skip it break; } // end switch mmioSeek( cfp, next_chunk, SEEK_SET ); } // At this stage, examine source format, and set up WAVEFORATEX structure for DirectSound. // Since DirectSound only supports PCM, force this structure to be PCM compliant. We will // need to convert data on the fly later if our souce is not PCM switch ( m_pwfmt_original->wFormatTag ) { case WAVE_FORMAT_PCM: m_wave_format = WAVE_FORMAT_PCM; m_wfmt.wBitsPerSample = m_pwfmt_original->wBitsPerSample; break; case WAVE_FORMAT_ADPCM: m_wave_format = WAVE_FORMAT_ADPCM; m_wfmt.wBitsPerSample = 16; break; default: nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n")); //Int3(); goto OPEN_ERROR; break; } // end switch // Set up the WAVEFORMATEX structure to have the right PCM characteristics m_wfmt.wFormatTag = WAVE_FORMAT_PCM; m_wfmt.nChannels = m_pwfmt_original->nChannels; m_wfmt.nSamplesPerSec = m_pwfmt_original->nSamplesPerSec; m_wfmt.cbSize = 0; m_wfmt.nBlockAlign = (unsigned short)(( m_wfmt.nChannels * m_wfmt.wBitsPerSample ) / 8); m_wfmt.nAvgBytesPerSec = m_wfmt.nBlockAlign * m_wfmt.nSamplesPerSec; // Init some member data from format chunk m_nBlockAlign = m_pwfmt_original->nBlockAlign; m_nUncompressedAvgDataRate = m_wfmt.nAvgBytesPerSec; // Cue for streaming Cue (); // Successful open goto OPEN_DONE; OPEN_ERROR: // Handle all errors here nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n",pszFilename)); fRtn = FAILURE; if (cfp != NULL) { // Close file mmioClose( cfp, 0 ); cfp = NULL; } if (m_pwfmt_original) { free(m_pwfmt_original); m_pwfmt_original = NULL; } OPEN_DONE: return (fRtn); }
//----------------------------------------------------------------------------- // Name: CWaveFile::ReadMMIO() // Desc: Support function for reading from a multimedia I/O stream. // m_hmmio must be valid before calling. This function uses it to // update m_ckRiff, and m_pwfx. //----------------------------------------------------------------------------- HRESULT WaveDecoder::ReadMMIO() { MMCKINFO ckIn; // chunk info. for general use. PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. memset( &ckIn, 0, sizeof(ckIn) ); m_pwfx = NULL; if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) ) //return DXTRACE_ERR( L"mmioDescend", E_FAIL ); return E_FAIL; // Check to make sure this is a valid wave file if( ( m_ckRiff.ckid != FOURCC_RIFF ) || ( m_ckRiff.fccType != mmioFOURCC( 'W', 'A', 'V', 'E' ) ) ) //return DXTRACE_ERR( L"mmioFOURCC", E_FAIL ); return E_FAIL; // Search the input file for for the 'fmt ' chunk. ckIn.ckid = mmioFOURCC( 'f', 'm', 't', ' ' ); if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) ) //return DXTRACE_ERR( L"mmioDescend", E_FAIL ); return E_FAIL; // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>; // if there are extra parameters at the end, we'll ignore them if( ckIn.cksize < ( LONG )sizeof( PCMWAVEFORMAT ) ) //return DXTRACE_ERR( L"sizeof(PCMWAVEFORMAT)", E_FAIL ); return E_FAIL; // Read the 'fmt ' chunk into <pcmWaveFormat>. if( mmioRead( m_hmmio, ( HPSTR )&pcmWaveFormat, sizeof( pcmWaveFormat ) ) != sizeof( pcmWaveFormat ) ) //return DXTRACE_ERR( L"mmioRead", E_FAIL ); return E_FAIL; // Allocate the waveformatex, but if its not pcm format, read the next // word, and thats how many extra bytes to allocate. if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM ) { m_pwfx = ( WAVEFORMATEX* )new CHAR[ sizeof( WAVEFORMATEX ) ]; if( NULL == m_pwfx ) //return DXTRACE_ERR( L"m_pwfx", E_FAIL ); return E_FAIL; // Copy the bytes from the pcm structure to the waveformatex structure memcpy( m_pwfx, &pcmWaveFormat, sizeof( pcmWaveFormat ) ); m_pwfx->cbSize = 0; } else { // Read in length of extra bytes. WORD cbExtraBytes = 0L; if( mmioRead( m_hmmio, ( CHAR* )&cbExtraBytes, sizeof( WORD ) ) != sizeof( WORD ) ) //return DXTRACE_ERR( L"mmioRead", E_FAIL ); return E_FAIL; m_pwfx = ( WAVEFORMATEX* )new CHAR[ sizeof( WAVEFORMATEX ) + cbExtraBytes ]; if( NULL == m_pwfx ) //return DXTRACE_ERR( L"new", E_FAIL ); return E_FAIL; // Copy the bytes from the pcm structure to the waveformatex structure memcpy( m_pwfx, &pcmWaveFormat, sizeof( pcmWaveFormat ) ); m_pwfx->cbSize = cbExtraBytes; // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. if( mmioRead( m_hmmio, ( CHAR* )( ( ( BYTE* )&( m_pwfx->cbSize ) ) + sizeof( WORD ) ), cbExtraBytes ) != cbExtraBytes ) { SAFE_DELETE( m_pwfx ); //return DXTRACE_ERR( L"mmioRead", E_FAIL ); return E_FAIL; } } // Ascend the input file out of the 'fmt ' chunk. if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) ) { SAFE_DELETE( m_pwfx ); //return DXTRACE_ERR( L"mmioAscend", E_FAIL ); return E_FAIL; } return S_OK; }
static BOOL MCIAVI_GetInfoVideo(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCKINFO* mmckStream) { MMCKINFO mmckInfo; TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_video.fccType)), HIBYTE(LOWORD(wma->ash_video.fccType)), LOBYTE(HIWORD(wma->ash_video.fccType)), HIBYTE(HIWORD(wma->ash_video.fccType))); TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_video.fccHandler)), HIBYTE(LOWORD(wma->ash_video.fccHandler)), LOBYTE(HIWORD(wma->ash_video.fccHandler)), HIBYTE(HIWORD(wma->ash_video.fccHandler))); TRACE("ash.dwFlags=%d\n", wma->ash_video.dwFlags); TRACE("ash.wPriority=%d\n", wma->ash_video.wPriority); TRACE("ash.wLanguage=%d\n", wma->ash_video.wLanguage); TRACE("ash.dwInitialFrames=%d\n", wma->ash_video.dwInitialFrames); TRACE("ash.dwScale=%d\n", wma->ash_video.dwScale); TRACE("ash.dwRate=%d\n", wma->ash_video.dwRate); TRACE("ash.dwStart=%d\n", wma->ash_video.dwStart); TRACE("ash.dwLength=%d\n", wma->ash_video.dwLength); TRACE("ash.dwSuggestedBufferSize=%d\n", wma->ash_video.dwSuggestedBufferSize); TRACE("ash.dwQuality=%d\n", wma->ash_video.dwQuality); TRACE("ash.dwSampleSize=%d\n", wma->ash_video.dwSampleSize); TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", wma->ash_video.rcFrame.top, wma->ash_video.rcFrame.left, wma->ash_video.rcFrame.bottom, wma->ash_video.rcFrame.right); /* rewind to the start of the stream */ mmioAscend(wma->hFile, mmckStream, 0); mmckInfo.ckid = ckidSTREAMFORMAT; if (mmioDescend(wma->hFile, &mmckInfo, mmckList, MMIO_FINDCHUNK) != 0) { WARN("Can't find 'strf' chunk\n"); return FALSE; } wma->inbih = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize); if (!wma->inbih) { WARN("Can't alloc input BIH\n"); return FALSE; } mmioRead(wma->hFile, (LPSTR)wma->inbih, mmckInfo.cksize); TRACE("bih.biSize=%d\n", wma->inbih->biSize); TRACE("bih.biWidth=%d\n", wma->inbih->biWidth); TRACE("bih.biHeight=%d\n", wma->inbih->biHeight); TRACE("bih.biPlanes=%d\n", wma->inbih->biPlanes); TRACE("bih.biBitCount=%d\n", wma->inbih->biBitCount); TRACE("bih.biCompression=%x\n", wma->inbih->biCompression); TRACE("bih.biSizeImage=%d\n", wma->inbih->biSizeImage); TRACE("bih.biXPelsPerMeter=%d\n", wma->inbih->biXPelsPerMeter); TRACE("bih.biYPelsPerMeter=%d\n", wma->inbih->biYPelsPerMeter); TRACE("bih.biClrUsed=%d\n", wma->inbih->biClrUsed); TRACE("bih.biClrImportant=%d\n", wma->inbih->biClrImportant); wma->source.left = 0; wma->source.top = 0; wma->source.right = wma->inbih->biWidth; wma->source.bottom = wma->inbih->biHeight; wma->dest = wma->source; return TRUE; }
//----------------------------------------------------------------------------- bool AudioFile::Load() { #if MAC AudioFileID mAudioFileID; AudioStreamBasicDescription fileDescription, outputFormat; SInt64 dataSize64; UInt32 dataSize; OSStatus err; UInt32 size; // ファイルを開く FSRef ref; Boolean isDirectory=false; FSPathMakeRef((const UInt8*)GetFilePath(), &ref, &isDirectory); err = AudioFileOpen(&ref, fsRdPerm, 0, &mAudioFileID); if (err) { //NSLog(@"AudioFileOpen failed"); return false; } // 開いたファイルの基本情報を fileDescription へ size = sizeof(AudioStreamBasicDescription); err = AudioFileGetProperty(mAudioFileID, kAudioFilePropertyDataFormat, &size, &fileDescription); if (err) { //NSLog(@"AudioFileGetProperty failed"); AudioFileClose(mAudioFileID); return false; } // 開いたファイルのデータ部のバイト数を dataSize へ size = sizeof(SInt64); err = AudioFileGetProperty(mAudioFileID, kAudioFilePropertyAudioDataByteCount, &size, &dataSize64); if (err) { //NSLog(@"AudioFileGetProperty failed"); AudioFileClose(mAudioFileID); return false; } dataSize = static_cast<UInt32>(dataSize64); AudioFileTypeID fileTypeID; size = sizeof( AudioFileTypeID ); err = AudioFileGetProperty(mAudioFileID, kAudioFilePropertyFileFormat, &size, &fileTypeID); if (err) { //NSLog(@"AudioFileGetProperty failed"); AudioFileClose(mAudioFileID); return false; } // Instrument情報を初期化 mInstData.basekey = 60; mInstData.lowkey = 0; mInstData.highkey = 127; mInstData.loop = 0; //ループポイントの取得 Float64 st_point=0.0,end_point=0.0; if ( fileTypeID == kAudioFileAIFFType || fileTypeID == kAudioFileAIFCType ) { //INSTチャンクの取得 AudioFileGetUserDataSize(mAudioFileID, 'INST', 0, &size); if ( size > 4 ) { UInt8 *instChunk = new UInt8[size]; AudioFileGetUserData(mAudioFileID, 'INST', 0, &size, instChunk); //MIDI情報の取得 mInstData.basekey = instChunk[0]; mInstData.lowkey = instChunk[2]; mInstData.highkey = instChunk[3]; if ( instChunk[9] > 0 ) { //ループフラグを確認 //マーカーの取得 UInt32 writable; err = AudioFileGetPropertyInfo(mAudioFileID, kAudioFilePropertyMarkerList, &size, &writable); if (err) { //NSLog(@"AudioFileGetPropertyInfo failed"); AudioFileClose(mAudioFileID); return NULL; } UInt8 *markersBuffer = new UInt8[size]; AudioFileMarkerList *markers = reinterpret_cast<AudioFileMarkerList*>(markersBuffer); err = AudioFileGetProperty(mAudioFileID, kAudioFilePropertyMarkerList, &size, markers); if (err) { //NSLog(@"AudioFileGetProperty failed"); AudioFileClose(mAudioFileID); return NULL; } //ループポイントの設定 for (unsigned int i=0; i<markers->mNumberMarkers; i++) { if (markers->mMarkers[i].mMarkerID == instChunk[11] ) { st_point = markers->mMarkers[i].mFramePosition; } else if (markers->mMarkers[i].mMarkerID == instChunk[13] ) { end_point = markers->mMarkers[i].mFramePosition; } CFRelease(markers->mMarkers[i].mName); } if ( st_point < end_point ) { mInstData.loop = 1; } delete [] markersBuffer; } delete [] instChunk; } } else if ( fileTypeID == kAudioFileWAVEType ) { //smplチャンクの取得 AudioFileGetUserDataSize( mAudioFileID, 'smpl', 0, &size ); if ( size >= sizeof(WAV_smpl) ) { UInt8 *smplChunk = new UInt8[size]; AudioFileGetUserData( mAudioFileID, 'smpl', 0, &size, smplChunk ); WAV_smpl *smpl = (WAV_smpl *)smplChunk; smpl->loops = EndianU32_LtoN( smpl->loops ); if ( smpl->loops > 0 ) { mInstData.loop = true; mInstData.basekey = EndianU32_LtoN( smpl->note ); st_point = EndianU32_LtoN( smpl->start ); end_point = EndianU32_LtoN( smpl->end ) + 1; //SoundForge等では最終ポイントを含める解釈 //end_point = EndianU32_LtoN( smpl->end ); //PeakではなぜかAIFFと同じ } else { mInstData.basekey = EndianU32_LtoN( smpl->note ); } delete [] smplChunk; } } //容量の制限 SInt64 dataSamples = dataSize / fileDescription.mBytesPerFrame; if ( dataSamples > MAXIMUM_SAMPLES ) { dataSize = MAXIMUM_SAMPLES * fileDescription.mBytesPerFrame; } if ( st_point > MAXIMUM_SAMPLES ) { st_point = MAXIMUM_SAMPLES; } if ( end_point > MAXIMUM_SAMPLES ) { end_point = MAXIMUM_SAMPLES; } // 波形一時読み込み用メモリを確保 char *fileBuffer; unsigned int fileBufferSize; if (mInstData.loop) { fileBufferSize = dataSize+EXPAND_BUFFER*fileDescription.mBytesPerFrame; } else { fileBufferSize = dataSize; } fileBuffer = new char[fileBufferSize]; memset(fileBuffer, 0, fileBufferSize); // ファイルから波形データの読み込み err = AudioFileReadBytes(mAudioFileID, false, 0, &dataSize, fileBuffer); if (err) { //NSLog(@"AudioFileReadBytes failed"); AudioFileClose(mAudioFileID); delete [] fileBuffer; return false; } AudioFileClose(mAudioFileID); //ループを展開する Float64 adjustment = 1.0; outputFormat=fileDescription; if (mInstData.loop) { UInt32 plusalpha=0, framestocopy; while (plusalpha < EXPAND_BUFFER) { framestocopy = (end_point-st_point)>(EXPAND_BUFFER-plusalpha)?(EXPAND_BUFFER-plusalpha):end_point-st_point; memcpy(fileBuffer+((int)end_point+plusalpha)*fileDescription.mBytesPerFrame, fileBuffer+(int)st_point*fileDescription.mBytesPerFrame, framestocopy*fileDescription.mBytesPerFrame); plusalpha += framestocopy; } dataSize += plusalpha*fileDescription.mBytesPerFrame; //16サンプル境界にFIXする adjustment = ( (long long)((end_point-st_point)/16) ) / ((end_point-st_point)/16.0); st_point *= adjustment; end_point *= adjustment; } outputFormat.mFormatID = kAudioFormatLinearPCM; outputFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian; outputFormat.mChannelsPerFrame = 1; outputFormat.mBytesPerFrame = sizeof(float); outputFormat.mBitsPerChannel = 32; outputFormat.mBytesPerPacket = outputFormat.mBytesPerFrame; // バイトオーダー変換用のコンバータを用意 AudioConverterRef converter; err = AudioConverterNew(&fileDescription, &outputFormat, &converter); if (err) { //NSLog(@"AudioConverterNew failed"); delete [] fileBuffer; return false; } //サンプリングレート変換の質を最高に設定 // if (fileDescription.mSampleRate != outputFormat.mSampleRate) { // size = sizeof(UInt32); // UInt32 setProp = kAudioConverterQuality_Max; // AudioConverterSetProperty(converter, kAudioConverterSampleRateConverterQuality, // size, &setProp); // // size = sizeof(UInt32); // setProp = kAudioConverterSampleRateConverterComplexity_Mastering; // AudioConverterSetProperty(converter, kAudioConverterSampleRateConverterComplexity, // size, &setProp); // // } //出力に必要十分なバッファサイズを得る UInt32 outputSize = dataSize; size = sizeof(UInt32); err = AudioConverterGetProperty(converter, kAudioConverterPropertyCalculateOutputBufferSize, &size, &outputSize); if (err) { //NSLog(@"AudioConverterGetProperty failed"); delete [] fileBuffer; AudioConverterDispose(converter); return false; } UInt32 monoSamples = outputSize/sizeof(float); // バイトオーダー変換 float *monoData = new float[monoSamples]; AudioConverterConvertBuffer(converter, dataSize, fileBuffer, &outputSize, monoData); if(outputSize == 0) { //NSLog(@"AudioConverterConvertBuffer failed"); delete [] fileBuffer; AudioConverterDispose(converter); return false; } //ループ長が16の倍数でない場合はサンプリングレート変換 Float64 inputSampleRate = fileDescription.mSampleRate; Float64 outputSampleRate = fileDescription.mSampleRate * adjustment; int outSamples = monoSamples; if ( outputSampleRate == inputSampleRate ) { m_pAudioData = new short[monoSamples]; for (int i=0; i<monoSamples; i++) { m_pAudioData[i] = static_cast<short>(monoData[i] * 32768); } } else { outSamples = static_cast<int>(monoSamples / (inputSampleRate / outputSampleRate)); m_pAudioData = new short[outSamples]; resampling(monoData, monoSamples, inputSampleRate, m_pAudioData, &outSamples, outputSampleRate); } // 後始末 delete [] monoData; delete [] fileBuffer; AudioConverterDispose(converter); //Instデータの設定 if ( st_point > MAXIMUM_SAMPLES ) { mInstData.lp = MAXIMUM_SAMPLES; } else { mInstData.lp = st_point; } if ( end_point > MAXIMUM_SAMPLES ) { mInstData.lp_end = MAXIMUM_SAMPLES; } else { mInstData.lp_end = end_point; } mInstData.srcSamplerate = outputSampleRate; mLoadedSamples = outSamples; mIsLoaded = true; return true; #else //Windowsのオーディオファイル読み込み処理 // ファイルを開く HMMIO hmio = NULL; MMRESULT err; DWORD size; hmio = mmioOpen( mPath, NULL, MMIO_READ ); if ( !hmio ) { return false; } // RIFFチャンクを探す MMCKINFO riffChunkInfo; riffChunkInfo.fccType = mmioFOURCC('W', 'A', 'V', 'E'); err = mmioDescend( hmio, &riffChunkInfo, NULL, MMIO_FINDRIFF ); if ( err != MMSYSERR_NOERROR ) { mmioClose( hmio, 0 ); return false; } if ( (riffChunkInfo.ckid != FOURCC_RIFF) || (riffChunkInfo.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) ) { mmioClose( hmio, 0 ); return false; } // フォーマットチャンクを探す MMCKINFO formatChunkInfo; formatChunkInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); err = mmioDescend( hmio, &formatChunkInfo, &riffChunkInfo, MMIO_FINDCHUNK ); if ( err != MMSYSERR_NOERROR ) { mmioClose( hmio, 0 ); return false; } if ( formatChunkInfo.cksize < sizeof(PCMWAVEFORMAT) ) { mmioClose( hmio, 0 ); return false; } //フォーマット情報を取得 WAVEFORMATEX pcmWaveFormat; DWORD fmsize = (formatChunkInfo.cksize > sizeof(WAVEFORMATEX)) ? sizeof(WAVEFORMATEX):formatChunkInfo.cksize; size = mmioRead( hmio, (HPSTR)&pcmWaveFormat, fmsize ); if ( size != fmsize ) { mmioClose( hmio, 0 ); return false; } if ( pcmWaveFormat.wFormatTag != WAVE_FORMAT_PCM ) { mmioClose( hmio, 0 ); return false; } mmioAscend(hmio, &formatChunkInfo, 0); // Instrument情報を初期化 mInstData.basekey = 60; mInstData.lowkey = 0; mInstData.highkey = 127; mInstData.loop = 0; //smplチャンクを探す MMCKINFO smplChunkInfo; smplChunkInfo.ckid = mmioFOURCC('s', 'm', 'p', 'l'); err = mmioDescend( hmio, &smplChunkInfo, &riffChunkInfo, MMIO_FINDCHUNK ); if ( err != MMSYSERR_NOERROR ) { smplChunkInfo.cksize = 0; } double st_point=0.0; double end_point=0.0; if ( smplChunkInfo.cksize >= sizeof(WAV_smpl) ) { //ループポイントの取得 unsigned char *smplChunk = new unsigned char[smplChunkInfo.cksize]; size = mmioRead(hmio,(HPSTR)smplChunk, smplChunkInfo.cksize); WAV_smpl *smpl = (WAV_smpl *)smplChunk; if ( smpl->loops > 0 ) { mInstData.loop = 1; mInstData.basekey = smpl->note; st_point = smpl->start; end_point = smpl->end + 1; //SoundForge等では最終ポイントを含める解釈 } else { mInstData.basekey = smpl->note; } delete [] smplChunk; } mmioAscend(hmio, &formatChunkInfo, 0); //dataチャンクを探す MMCKINFO dataChunkInfo; dataChunkInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); err = mmioDescend( hmio, &dataChunkInfo, &riffChunkInfo, MMIO_FINDCHUNK ); if( err != MMSYSERR_NOERROR ) { mmioClose( hmio, 0 ); return false; } // 波形一時読み込み用メモリを確保 unsigned int dataSize = dataChunkInfo.cksize; int bytesPerSample = pcmWaveFormat.nBlockAlign; char *fileBuffer; unsigned int fileBufferSize; //容量制限 int dataSamples = dataSize / pcmWaveFormat.nBlockAlign; if ( dataSamples > MAXIMUM_SAMPLES ) { dataSize = MAXIMUM_SAMPLES * pcmWaveFormat.nBlockAlign; } if ( st_point > MAXIMUM_SAMPLES ) { st_point = MAXIMUM_SAMPLES; } if ( end_point > MAXIMUM_SAMPLES ) { end_point = MAXIMUM_SAMPLES; } if (mInstData.loop) { fileBufferSize = dataSize+EXPAND_BUFFER*bytesPerSample; } else { fileBufferSize = dataSize; } fileBuffer = new char[fileBufferSize]; memset(fileBuffer, 0, fileBufferSize); // ファイルから波形データの読み込み size = mmioRead(hmio, (HPSTR)fileBuffer, dataSize); if ( size != dataSize ) { mmioClose( hmio, 0 ); return false; } mmioClose(hmio,0); //ループを展開する double inputSampleRate = pcmWaveFormat.nSamplesPerSec; double outputSampleRate = inputSampleRate; if (mInstData.loop) { unsigned int plusalpha=0; double framestocopy; while (plusalpha < EXPAND_BUFFER) { framestocopy = (end_point-st_point)>(EXPAND_BUFFER-plusalpha)?(EXPAND_BUFFER-plusalpha):end_point-st_point; memcpy(fileBuffer+((int)end_point+plusalpha)*bytesPerSample, fileBuffer+(int)st_point*bytesPerSample, static_cast<size_t>(framestocopy*bytesPerSample)); plusalpha += static_cast<unsigned int>(framestocopy); } dataSize += plusalpha*bytesPerSample; //16サンプル境界にFIXする double adjustment = ( (long long)((end_point-st_point)/16) ) / ((end_point-st_point)/16.0); outputSampleRate *= adjustment; st_point *= adjustment; end_point *= adjustment; } //一旦floatモノラルデータに変換 int bytesPerChannel = bytesPerSample / pcmWaveFormat.nChannels; unsigned int inputPtr = 0; unsigned int outputPtr = 0; int monoSamples = dataSize / bytesPerSample; float range = static_cast<float>((1<<(bytesPerChannel*8-1)) * pcmWaveFormat.nChannels); float *monoData = new float[monoSamples]; while (inputPtr < dataSize) { int frameSum = 0; for (int ch=0; ch<pcmWaveFormat.nChannels; ch++) { for (int i=0; i<bytesPerChannel; i++) { if (i<bytesPerChannel-1) { frameSum += (unsigned char)fileBuffer[inputPtr] << (8*i); } else { frameSum += fileBuffer[inputPtr] << (8*i); } inputPtr++; } } monoData[outputPtr] = frameSum / range; outputPtr++; } //ループ長が16の倍数でない場合はサンプリングレート変換 int outSamples = monoSamples; if ( outputSampleRate == inputSampleRate ) { m_pAudioData = new short[monoSamples]; for (int i=0; i<monoSamples; i++) { m_pAudioData[i] = static_cast<short>(monoData[i] * 32768); } } else { outSamples = static_cast<int>(monoSamples / (inputSampleRate / outputSampleRate)); m_pAudioData = new short[outSamples]; resampling(monoData, monoSamples, inputSampleRate, m_pAudioData, &outSamples, outputSampleRate); } // 後始末 delete [] fileBuffer; delete [] monoData; //Instデータの設定 mInstData.lp = static_cast<int>(st_point); mInstData.lp_end = static_cast<int>(end_point); mInstData.srcSamplerate = outputSampleRate; mLoadedSamples = outSamples; mIsLoaded = true; return true; #endif }
//----------------------------------------------------------------------------- // Name: ReadMMIO() // Desc: Support function for reading from a multimedia I/O stream //----------------------------------------------------------------------------- HRESULT ReadMMIO(HMMIO hmmioIn, MMCKINFO* pckInRIFF, WAVEFORMATEX** ppwfxInfo) { MMCKINFO ckIn; // chunk info. for general use. PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. *ppwfxInfo = NULL; if ((0 != mmioDescend(hmmioIn, pckInRIFF, NULL, 0))) return E_FAIL; if ((pckInRIFF->ckid != FOURCC_RIFF) || (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E'))) return E_FAIL; // Search the input file for for the 'fmt ' chunk. ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); if (0 != mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK)) return E_FAIL; // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>; // if there are extra parameters at the end, we'll ignore them if (ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT)) return E_FAIL; // Read the 'fmt ' chunk into <pcmWaveFormat>. if (mmioRead(hmmioIn, (HPSTR)&pcmWaveFormat, sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat)) return E_FAIL; // Allocate the waveformatex, but if its not pcm format, read the next // word, and thats how many extra bytes to allocate. if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) { if (NULL == (*ppwfxInfo = new WAVEFORMATEX)) return E_FAIL; // Copy the bytes from the pcm structure to the waveformatex structure memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat)); (*ppwfxInfo)->cbSize = 0; } else { // Read in length of extra bytes. WORD cbExtraBytes = 0L; if (mmioRead(hmmioIn, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD)) return E_FAIL; *ppwfxInfo = (WAVEFORMATEX*)new CHAR[sizeof(WAVEFORMATEX) + cbExtraBytes]; if (NULL == *ppwfxInfo) return E_FAIL; // Copy the bytes from the pcm structure to the waveformatex structure memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat)); (*ppwfxInfo)->cbSize = cbExtraBytes; // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. if (mmioRead(hmmioIn, (CHAR*)(((BYTE*)&((*ppwfxInfo)->cbSize)) + sizeof(WORD)), cbExtraBytes) != cbExtraBytes) { delete *ppwfxInfo; *ppwfxInfo = NULL; return E_FAIL; } } // Ascend the input file out of the 'fmt ' chunk. if (0 != mmioAscend(hmmioIn, &ckIn, 0)) { delete *ppwfxInfo; *ppwfxInfo = NULL; return E_FAIL; } return S_OK; }
int CWavFile::CheckValidity(HMMIO& hWaveFile, CString strFilePath, WAVEFORMATEX& wfx) { MMRESULT mmResult = 0; DWORD dwFmtSize = 0; LPTSTR pszFilePath = strdup(strFilePath); hWaveFile = mmioOpen(pszFilePath, NULL, MMIO_READ); if(hWaveFile == NULL) { MyMessageBox(_T("Open the wav file failed"), eERR_INFO); return -1; } // Descend 'wave' chunk m_mmckinfoParent.fccType = mmioFOURCC('W','A','V','E'); mmResult = mmioDescend(hWaveFile, &m_mmckinfoParent, NULL, MMIO_FINDRIFF); if(mmResult) { MyMessageBox(_T("It is not a wave format file"), eERR_INFO); return -1; } // Desecnd 'fmt ' chunk m_mmckinfoSubChunk.ckid = mmioFOURCC('f', 'm', 't', ' '); mmResult = mmioDescend(hWaveFile, &m_mmckinfoSubChunk, &m_mmckinfoParent, MMIO_FINDCHUNK); if(mmResult) { MyMessageBox(_T("Can't find the fmt chunk"), eERR_INFO); return -1; } // Read 'fmt ' chunk dwFmtSize = m_mmckinfoSubChunk.cksize; if((unsigned long)mmioRead(hWaveFile, (HPSTR)&wfx, dwFmtSize) != dwFmtSize) { MyMessageBox(_T("Read format chunk failed"), eERR_INFO); return -1; } // Ascend the 'fmt ' chunk mmResult = mmioAscend(hWaveFile, &m_mmckinfoSubChunk, 0); if(mmResult) { MyMessageBox(_T("Ascend fmt chunk failed"), eERR_INFO); return -1; } // Descend the 'data' chunk m_mmckinfoSubChunk.ckid = mmioFOURCC('d','a','t','a'); mmResult = mmioDescend(hWaveFile, &m_mmckinfoSubChunk, &m_mmckinfoParent, MMIO_FINDCHUNK); if(mmResult) { MyMessageBox(_T("Cannot find data chunk"), eERR_INFO); return -1; } else { m_dwDataSize = m_mmckinfoSubChunk.cksize; } return m_dwDataSize; }
/************************************************************************* * Name : PlayTheWave * * Description : This function initially opens the wave file to be played * and tells the MCD information about the file * that is about to be played. The Samples Per Second, * Bits Per Sample, and the number of channels with which * the waveform file was created has to be told to the MCD. * This function initially fills up the allocated buffer * of the playlist with the wave file. For 0 - MAXBUFF * the wave file is filled into the memory. The Wave file * is read in continously from 0 -MAXBUFF. * This same buffer is dynamically re-filled again and again * by the PlayThread thread. * * Concepts : The wave file is first opened and then continuously read * into the buffer. If the end of the wave file is reached * then we seek to the starting of the wave and keep on reading * the wave file till the buffer fills up. This displays the * double buffering concept because, while the playlist is * continuously looping and playing the wave file, the * playlist buffers are constantly being filled with data from * the wave file in the PlayThread thread. * * * * MMPM/2 API's : mmioOpen * mmioGetHeader * mmioRead * mmioSeek * mciSendCommand * MCI_SET * MCI_CUE * * Parameters : None. * * Return : ulReturn * *************************************************************************/ ULONG PlayTheWave() { MCI_WAVE_SET_PARMS lpWaveSet; ULONG ulReturn; MMAUDIOHEADER mmHeader; int i; long ulBytesRead; memset ( &lpWaveSet, 0, sizeof( MCI_WAVE_SET_PARMS ) ); /* Open the Wave File MyWave.Wav for Reading */ hmmioFileHandle = mmioOpen(WAVE_FILE_NAME, (PMMIOINFO) NULL, MMIO_READ); /* If the Wave File could not be opened */ if (!hmmioFileHandle) { ShowAMessage( IDS_ERROR_TITLE, IDS_CANT_OPEN_WAVE, MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP | MB_APPLMODAL, FALSE ); return ( TRUE ); } /* * Get the Header Information for the file so that we can set the channels, * Samples Per Second and Bits Per Sample to play the memory playlist. */ ulReturn = mmioGetHeader(hmmioFileHandle, (PVOID) &mmHeader, sizeof(MMAUDIOHEADER), (PLONG) &ulBytesRead, (ULONG) NULL, (ULONG) NULL); if (ulReturn != 0 ) return ( ulReturn ); /* Set the WaveSet Structure */ lpWaveSet.ulLevel = 100; lpWaveSet.ulSamplesPerSec = mmHeader.mmXWAVHeader.WAVEHeader.ulSamplesPerSec; lpWaveSet.usBitsPerSample = mmHeader.mmXWAVHeader.WAVEHeader.usBitsPerSample; lpWaveSet.usChannels = mmHeader.mmXWAVHeader.WAVEHeader.usChannels; lpWaveSet.ulAudio = MCI_SET_AUDIO_ALL; lpWaveSet.hwndCallback = (HWND) NULL; /* Set the Channels for the MCD */ ulReturn = mciSendCommand(usWaveDeviceId, MCI_SET, MCI_WAIT | MCI_WAVE_SET_CHANNELS, (PVOID) &lpWaveSet, (USHORT)NULL); if (ulReturn != 0 ) return ( ulReturn ); /* Set the Samples Per Second */ ulReturn = mciSendCommand(usWaveDeviceId, MCI_SET, MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC, (PVOID) &lpWaveSet, (USHORT)NULL); if (ulReturn != 0 ) return ( ulReturn ); /* Set the Bits per Sample */ ulReturn = mciSendCommand(usWaveDeviceId, MCI_SET, MCI_WAIT | MCI_WAVE_SET_BITSPERSAMPLE, (PVOID) &lpWaveSet, (USHORT)NULL); if (ulReturn != 0 ) return ( ulReturn ); /* From 0 - MAXBUFF, fill the memory Playlist buffer with the wave file. */ for (i=0; i<MAXBUFF; i++) { ulBytesRead = mmioRead(hmmioFileHandle, (HPSTR) achDataBuffer[i], MAXSIZE); /* * If the end of the wave file is reached then Seek to the starting * of the wave file and start reading the wave into the appropriate * buffer */ if (ulBytesRead < MAXSIZE) { mmioSeek(hmmioFileHandle, 0, SEEK_SET); ulBytesRead = mmioRead(hmmioFileHandle, (HPSTR) achDataBuffer[i], MAXSIZE); } } /* * Create the thread that will maintain the playlist buffer */ fEndPlay = FALSE; if ( DosCreateThread ( &tidPlayThread, (PFNTHREAD) PlayThread, 0L, 0L, 8192L)) return ( TRUE ); return ( FALSE ); }
ALERROR CSoundMgr::LoadWaveFile (HMMIO hFile, int *retiChannel) // LoadWaveFile // // Creates a sound buffer from an open MMIO file { ASSERT(m_pDS); MMCKINFO parent, child; ::ZeroMemory(&parent, sizeof(parent)); ::ZeroMemory(&child, sizeof(child)); // Descend into the RIFF parent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(hFile, &parent, NULL, MMIO_FINDRIFF)) { mmioClose(hFile, 0); return ERR_FAIL; } // Descend to the wave format child.ckid = mmioFOURCC('f', 'm', 't', ' '); if (mmioDescend(hFile, &child, &parent, 0)) { mmioClose(hFile, 0); return ERR_FAIL; } // Allocate a block large enough to hold the format size DWORD dwFmtSize = child.cksize; DWORD dwAllocSize = max(dwFmtSize, sizeof(WAVEFORMATEX)); WAVEFORMATEX *pFormat = (WAVEFORMATEX *)new char [dwAllocSize]; ::ZeroMemory(pFormat, dwAllocSize); if (mmioRead(hFile, (char *)pFormat, dwFmtSize) != (LONG)dwFmtSize) { delete [] (char *)pFormat; mmioClose(hFile, 0); return ERR_FAIL; } // Now descend to the data if (mmioAscend(hFile, &child, 0)) { delete [] (char *)pFormat; mmioClose(hFile, 0); return ERR_FAIL; } child.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(hFile, &child, &parent, MMIO_FINDCHUNK)) { delete [] (char *)pFormat; mmioClose(hFile, 0); return ERR_FAIL; } DWORD dwDataSize = child.cksize; // Create the DirectSound buffer DSBUFFERDESC dsbdesc; LPDIRECTSOUNDBUFFER pBuffer; ::ZeroMemory(&dsbdesc, sizeof(dsbdesc)); dsbdesc.dwSize = sizeof(dsbdesc); dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN; dsbdesc.dwBufferBytes = dwDataSize; dsbdesc.lpwfxFormat = pFormat; if (FAILED(m_pDS->CreateSoundBuffer(&dsbdesc, &pBuffer, NULL))) { // If we can't create the sound buffer, try creating the same buffer // but with no volume or pan controls. dsbdesc.dwFlags = 0; if (FAILED(m_pDS->CreateSoundBuffer(&dsbdesc, &pBuffer, NULL))) { delete [] (char *)pFormat; return ERR_FAIL; } } delete [] (char *)pFormat; // Now read into the buffer LPVOID pDest; DWORD dwDestSize; if (FAILED(pBuffer->Lock(0, 0, &pDest, &dwDestSize, NULL, NULL, DSBLOCK_ENTIREBUFFER))) { pBuffer->Release(); mmioClose(hFile, 0); return ERR_FAIL; } if (mmioRead(hFile, (char *)pDest, dwDestSize) != (LONG)dwDataSize) { pBuffer->Release(); mmioClose(hFile, 0); return ERR_FAIL; } // Done with the wave file mmioClose(hFile, 0); // Add to the channel int iChannel = AllocChannel(); SChannel *pChannel = GetChannel(iChannel); pChannel->pBuffer = pBuffer; pChannel->pNext = NULL; // Done if (retiChannel) *retiChannel = iChannel; return NOERROR; }
BOOL CAudioCtrl::OpenWaveFile(char *lpszWaveFileName) { if ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] ) return FALSE; m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = ::mmioOpen ( (LPTSTR)lpszWaveFileName,NULL,MMIO_READ ); if ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] == NULL ) { AfxMessageBox ( "Open wave file failed" ); return FALSE; } m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON].fccType = mmioFOURCC('W','A','V','E'); MMRESULT mmResult = ::mmioDescend(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON],NULL,MMIO_FINDRIFF); if(mmResult) { AfxMessageBox("Error descending into file"); ::mmioClose(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],0); m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL; return FALSE; } m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON].ckid = mmioFOURCC('f','m','t',' '); mmResult = mmioDescend(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],&m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON],&m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON],MMIO_FINDCHUNK); if(mmResult) { AfxMessageBox("Error descending in wave file"); mmioClose(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],0); m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL; return FALSE; } DWORD bytesRead = mmioRead ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],(LPSTR)&m_Format, m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON].cksize ); if ( bytesRead < 0 ) { AfxMessageBox ( "Error reading PCM wave format record" ); mmioClose ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], 0 ); return FALSE; } if ( !SetRelateParaAfterGetWaveFormat () ) return FALSE; // open output sound file mmResult = mmioAscend ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON], 0 ); if ( mmResult ) { AfxMessageBox ( "Error ascending in File" ); mmioClose ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], 0 ); m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL; return FALSE; } m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON].ckid = mmioFOURCC('d','a','t','a'); mmResult = mmioDescend ( m_hWaveFile[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoChild[ENUM_FILE_CHANNEL_COMMON], &m_MMCKInfoParent[ENUM_FILE_CHANNEL_COMMON], MMIO_FINDCHUNK ); if ( mmResult ) { AfxMessageBox("error reading data chunk"); mmioClose(m_hWaveFile[ENUM_FILE_CHANNEL_COMMON],0); m_hWaveFile[ENUM_FILE_CHANNEL_COMMON] = NULL; return FALSE; } return TRUE; }
VOID APIENTRY PlayThread ( ULONG parm1 ) { ULONG ulBytesRead; ULONG ulBufferNum; ULONG ulPostCount; ULONG ulReturn; MCI_PLAY_PARMS mciPlayParameters; mciPlayParameters.hwndCallback = hwndDiag; /* * Send the Play Command to begin the playing of the memory playlist. */ ulReturn = mciSendCommand(usWaveDeviceId, MCI_PLAY, MCI_NOTIFY, (PVOID) &mciPlayParameters, 0); /* * Loop until the playlist is stopped. */ while( !fEndPlay ) { for( ulBufferNum = 0; ulBufferNum < MAXBUFF; ulBufferNum++ ) { /* * Use DosWaitEventSem to pause util the playlist plays this * buffer. Then refill the buffer and post the semaphore. */ ulReturn = DosWaitEventSem ( hevSem[ulBufferNum], 5000L ); DosResetEventSem ( hevSem[ulBufferNum], &ulPostCount ); if( fEndPlay ) break; /* * Read the Next MAXSIZE bytes of the wave file */ ulBytesRead = mmioRead(hmmioFileHandle, (HPSTR) achDataBuffer[ulBufferNum], MAXSIZE); /* * If we have reached the end of the wave file then set the file marker * to the begining of the file and start reading into the bufferno. * This causes the continuous filling and playing of the data buffer * again and again as long as the END push button is not pressed. * The wave file is going to keep on playing without any interruptions * util ther user selects the stop button. */ if (ulBytesRead < MAXSIZE) { /* Seek to the starting of the wave file */ mmioSeek(hmmioFileHandle, 0, SEEK_SET); /* Read the Next MAXSIZE bytes of the wave file */ mmioRead(hmmioFileHandle, (HPSTR) achDataBuffer[ulBufferNum], MAXSIZE); } } /* End of for loop */ } /* End of while loop */ } /* End of function PlayThread */
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 int read_word(HMMIO rw, WORD *i) { int rc = mmioRead( rw, (char *)i, sizeof(WORD) ); IF_ERR(rc != sizeof(WORD), 0); return 1; }
static int read_ubyte(HMMIO rw, ubyte *i) { int rc = mmioRead( rw, (char *)i, sizeof(ubyte) ); IF_ERR(rc != sizeof(ubyte), 0); return 1; }
//WAVEファイルをロードする int WaveLoader::ReadWaveData(WAVEFORMATEX* wfx, void** pdata, QWORD dwFrom, QWORD dwSizeToRead, bool isLoopWave) { static MMCKINFO parent, child; static char szBefore[MAX_PATH]; _ASSERT(m_FileInfo->name); if(pdata!=NULL) SAFE_GLOBALFREE(*pdata); //if(m_hmmio!=NULL && lstrcmp(m_FileInfo->name, szBefore)!=0){//ファイル名が指定されていたら開きなおす // SAFE_MMIOCLOSE(m_hmmio); //} if( !isLoaded ){ lstrcpy(szBefore, m_FileInfo->name); if( lstrcmp(m_FileInfo->name, CSL_LOAD_MEMORYIMAGE)==0 ){ // if(!m_hmmio){//最初の一回しかしない処理(ストリーミング用の処置) MMIOINFO mmioinfo; ZeroMemory(&mmioinfo, sizeof(MMIOINFO)); mmioinfo.pchBuffer = (HPSTR)m_FileInfo->pMemBuffer; mmioinfo.fccIOProc = FOURCC_MEM; mmioinfo.cchBuffer = m_FileInfo->fsize; if(NULL == (m_hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ|MMIO_ALLOCBUF))){ return CSL_E_UNEXP; } }else{ if(NULL == (m_hmmio = mmioOpen((LPSTR)m_FileInfo->name, NULL, MMIO_READ|MMIO_ALLOCBUF))){ return CSL_E_UNEXP; } } parent.fccType = mmioFOURCC('W', 'A', 'V', 'E');//waveファイルかどうか調べる if(mmioDescend(m_hmmio, &parent, NULL, MMIO_FINDRIFF) != MMSYSERR_NOERROR){ SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } child.ckid = mmioFOURCC('f', 'm', 't', ' ');//fmtチャンクへ移動する if(mmioDescend(m_hmmio, &child, &parent, MMIO_FINDCHUNK) != MMSYSERR_NOERROR){ SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } _ASSERT(wfx); if(mmioRead(m_hmmio, (HPSTR)wfx, (LONG)child.cksize) != (LONG)child.cksize){//fmtチャンク(WAVEFORMATEX)読み取り SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } _ASSERT((wfx->wFormatTag==WAVE_FORMAT_PCM)); mmioAscend(m_hmmio, &child, 0);//fmtチャンクから出る child.ckid = mmioFOURCC('d', 'a', 't', 'a');//dataチャンクに移動 if(mmioDescend(m_hmmio, &child, &parent, MMIO_FINDCHUNK) != MMSYSERR_NOERROR) { SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } m_dwDataLength = child.cksize;//WAVE領域のサイズ m_dwOffsetToWaveData = mmioSeek(m_hmmio, 0, SEEK_CUR);//データまでの位置を保存しておく } if(pdata){ if(dwSizeToRead<=0){//ファイル全体を読み込む (*pdata) = (LPBYTE)GlobalAlloc(GPTR, m_dwDataLength * sizeof(BYTE)); _ASSERT(*pdata); if(mmioRead(m_hmmio, (HPSTR)*pdata, (LONG)m_dwDataLength) != (LONG)m_dwDataLength){ GlobalFree(*pdata); SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } SAFE_MMIOCLOSE(m_hmmio); //必要なデータがそろったので、ファイルを閉じる m_dwCurrentDecodedPos += dwSizeToRead; }else{ //DWORD dwInnerFinPos = dwFrom + dwSizeToRead; ////領域サイズ以上だったら収まるように値を補正 //if(m_dwDataLength < dwInnerFinPos){ // dwSizeToRead -= dwInnerFinPos-m_dwDataLength; //} //開始位置が指定されていれば, データ領域からのオフセットをStartとする. //指定されていなければ, それまで進んだカーソル位置から読み込みを開始する if(dwFrom>=0) mmioSeek(m_hmmio, (LONG)(m_dwOffsetToWaveData + dwFrom), SEEK_SET); //要求領域分のメモリ確保 (*pdata) = (LPBYTE)GlobalAlloc(GPTR, (SIZE_T)(dwSizeToRead * sizeof(BYTE))); _ASSERT(*pdata); //現在位置からリクエストサイズを読むとオーバーするようなら、ラップアラウンドする。 DWORD dwNowCursor = mmioSeek(m_hmmio, 0, SEEK_CUR) - m_dwOffsetToWaveData; if(m_dwDataLength < (dwNowCursor + dwSizeToRead)){ if( !isLoopWave ){ if( dwNowCursor>=m_dwDataLength ){ FillMemory((BYTE*)*pdata, dwSizeToRead, (m_wfx.wBitsPerSample==8) ? 128:0); return CSL_E_OUTOFRANGE; } } DWORD dwBeforeWrapAround = m_dwDataLength-dwNowCursor; //とりあえず、最後まで読む if(mmioRead(m_hmmio, (HPSTR)*pdata, (LONG)dwBeforeWrapAround) != (LONG)dwBeforeWrapAround){ GlobalFree(*pdata); SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } m_dwCurrentDecodedPos += dwBeforeWrapAround; if(isLoopWave){//残った部分を無音で埋めるかどうか mmioSeek(m_hmmio, 0, SEEK_SET); mmioSeek(m_hmmio, m_dwOffsetToWaveData, SEEK_CUR); //ポインタをWAVE領域始点に戻す //ラップアラウンド分を読む if(mmioRead(m_hmmio, (HPSTR)*pdata+dwBeforeWrapAround, (LONG)(dwSizeToRead - dwBeforeWrapAround)) != (LONG)(dwSizeToRead - dwBeforeWrapAround)){ GlobalFree(*pdata); SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } m_dwCurrentDecodedPos = 0; m_dwCurrentDecodedPos += dwSizeToRead - dwBeforeWrapAround; }else{ FillMemory((BYTE*)*pdata+dwBeforeWrapAround, dwSizeToRead - dwBeforeWrapAround, (m_wfx.wBitsPerSample==8) ? 128:0); return CSL_N_FIN; } }else{ //ラップアラウンドしなかった場合 if(mmioRead(m_hmmio, (HPSTR)*pdata, (LONG)dwSizeToRead) != (LONG)dwSizeToRead){ GlobalFree(*pdata); SAFE_MMIOCLOSE(m_hmmio); return CSL_E_UNEXP; } m_dwCurrentDecodedPos += dwSizeToRead; }//必要なデータはまだあるので、ファイルは閉じない } } return CSL_E_OK; }
void CSoundMgr::Play (int iChannel, int iVolume, int iPan) // Play // // Plays a channel. // // iVolume = 0 for maximum volume. // iVolume = -10,000 for minimum volume. { if (m_pDS == NULL || m_iSoundVolume == 0) return; SChannel *pChannel = GetChannel(iChannel); if (pChannel->pBuffer == NULL) return; // If the buffer is lost, then we need to restore it DWORD dwStatus; pChannel->pBuffer->GetStatus(&dwStatus); if (dwStatus & DSBSTATUS_BUFFERLOST) { if (FAILED(pChannel->pBuffer->Restore())) return; if (pChannel->sFilename.IsBlank()) return; // Open the file MMCKINFO parent, child; ::ZeroMemory(&parent, sizeof(parent)); ::ZeroMemory(&child, sizeof(child)); HMMIO hFile = mmioOpen(pChannel->sFilename.GetASCIIZPointer(), NULL, MMIO_READ | MMIO_ALLOCBUF); if (hFile == NULL) return; // Descend into the RIFF parent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(hFile, &parent, NULL, MMIO_FINDRIFF)) { mmioClose(hFile, 0); return; } child.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(hFile, &child, &parent, MMIO_FINDCHUNK)) { mmioClose(hFile, 0); return; } DWORD dwDataSize = child.cksize; // Now read into the buffer LPVOID pDest; DWORD dwDestSize; if (FAILED(pChannel->pBuffer->Lock(0, 0, &pDest, &dwDestSize, NULL, NULL, DSBLOCK_ENTIREBUFFER))) { mmioClose(hFile, 0); return; } if (mmioRead(hFile, (char *)pDest, dwDestSize) != (LONG)dwDataSize) { mmioClose(hFile, 0); return; } // Done with the wave file mmioClose(hFile, 0); } // Check to see if the channel is busy. If it is, then we may need to create // a second buffer. else if (dwStatus & DSBSTATUS_PLAYING) { SChannel *pLastChannel = pChannel; pChannel = pChannel->pNext; while (pChannel) { pChannel->pBuffer->GetStatus(&dwStatus); if (!(dwStatus & DSBSTATUS_BUFFERLOST) && !(dwStatus & DSBSTATUS_PLAYING)) break; pLastChannel = pChannel; pChannel = pChannel->pNext; } // If we couldn't find another channel, then duplicate the original if (pChannel == NULL) { pChannel = GetChannel(iChannel); LPDIRECTSOUNDBUFFER pNewBuffer = NULL; if (FAILED(m_pDS->DuplicateSoundBuffer(pChannel->pBuffer, &pNewBuffer))) return; SChannel *pNewChannel = new SChannel; pLastChannel->pNext = pNewChannel; pNewChannel->pBuffer = pNewBuffer; pNewChannel->pNext = NULL; pChannel = pNewChannel; } } // Adjust volume int iVolumeAdj = MAX_VOLUME_LEVEL - m_iSoundVolume; int iMaxVolume = -(iVolumeAdj * VOLUME_STEP); int iVolumeRange = iMaxVolume - MIN_VOLUME; iVolume = iMaxVolume - ((iVolumeRange * iVolume) / MIN_VOLUME); // pChannel now points to a valid buffer. Play it! pChannel->pBuffer->SetVolume(iVolume); pChannel->pBuffer->SetPan(iPan); pChannel->pBuffer->Play(0, 0, 0); // Clean-up any channels after us that are done playing SChannel *pLastChannel = pChannel; pChannel = pChannel->pNext; while (pChannel) { pChannel->pBuffer->GetStatus(&dwStatus); if (!(dwStatus & DSBSTATUS_PLAYING)) { pChannel->pBuffer->Release(); pLastChannel->pNext = pChannel->pNext; delete pChannel; pChannel = pLastChannel->pNext; } else { pLastChannel = pChannel; pChannel = pChannel->pNext; } } }
/************************************************************************** * mmioDescend [WINMM.@] */ MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, const MMCKINFO* lpckParent, UINT uFlags) { DWORD dwOldPos; FOURCC srchCkId; FOURCC srchType; TRACE("(%p, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags); if (lpck == NULL) return MMSYSERR_INVALPARAM; dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); TRACE("dwOldPos=%d\n", dwOldPos); if (lpckParent != NULL) { TRACE("seek inside parent at %d !\n", lpckParent->dwDataOffset); /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */ if (dwOldPos < lpckParent->dwDataOffset || dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) { WARN("outside parent chunk\n"); return MMIOERR_CHUNKNOTFOUND; } } /* The SDK docu says 'ckid' is used for all cases. Real World * examples disagree -Marcus,990216. */ srchCkId = 0; srchType = 0; /* find_chunk looks for 'ckid' */ if (uFlags & MMIO_FINDCHUNK) srchCkId = lpck->ckid; /* find_riff and find_list look for 'fccType' */ if (uFlags & MMIO_FINDLIST) { srchCkId = FOURCC_LIST; srchType = lpck->fccType; } if (uFlags & MMIO_FINDRIFF) { srchCkId = FOURCC_RIFF; srchType = lpck->fccType; } TRACE("searching for %4.4s.%4.4s\n", (LPCSTR)&srchCkId, srchType ? (LPCSTR)&srchType : "any"); while (TRUE) { LONG ix; ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)); if (ix < 2*sizeof(DWORD)) { mmioSeek(hmmio, dwOldPos, SEEK_SET); WARN("return ChunkNotFound\n"); return MMIOERR_CHUNKNOTFOUND; } lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); TRACE("ckid=%4.4s fcc=%4.4s cksize=%08X !\n", (LPCSTR)&lpck->ckid, srchType ? (LPCSTR)&lpck->fccType:"<na>", lpck->cksize); if ( (!srchCkId || (srchCkId == lpck->ckid)) && (!srchType || (srchType == lpck->fccType)) ) break; dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1); mmioSeek(hmmio, dwOldPos, SEEK_SET); } lpck->dwFlags = 0; /* If we were looking for RIFF/LIST chunks, the final file position * is after the chunkid. If we were just looking for the chunk * it is after the cksize. So add 4 in RIFF/LIST case. */ if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) mmioSeek(hmmio, lpck->dwDataOffset + sizeof(DWORD), SEEK_SET); else { mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET); lpck->fccType = 0; } TRACE("lpck: ckid=%.4s, cksize=%d, dwDataOffset=%d fccType=%08X (%.4s)!\n", (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset, lpck->fccType, srchType?(LPSTR)&lpck->fccType:""); return MMSYSERR_NOERROR; }
int DSound_Load_WAV(const char *filename, int control_flags) { // this function loads a .wav file, sets up the directsound // buffer and loads the data into memory, the function returns // the id number of the sound HMMIO hwav; // handle to wave file MMCKINFO parent, // parent chunk child; // child chunk WAVEFORMATEX wfmtx; // wave format structure int sound_id = -1, // id of sound to be loaded index; // looping variable UCHAR *snd_buffer, // temporary sound buffer to hold voc data *audio_ptr_1=NULL, // data ptr to first write buffer *audio_ptr_2=NULL; // data ptr to second write buffer DWORD audio_length_1=0, // length of first write buffer audio_length_2=0; // length of second write buffer // step one: are there any open id's ? for (index=0; index < MAX_SOUNDS; index++) { // make sure this sound is unused if (sound_fx[index].state==SOUND_NULL) { sound_id = index; break; } } // did we get a free id? if (sound_id==-1) return(-1); // set up chunk info structure parent.ckid = (FOURCC)0; parent.cksize = 0; parent.fccType = (FOURCC)0; parent.dwDataOffset = 0; parent.dwFlags = 0; // copy data child = parent; // open the WAV file if ((hwav = mmioOpen((LPSTR)filename, NULL, MMIO_READ | MMIO_ALLOCBUF))==NULL) return(-1); // descend into the RIFF parent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(hwav, &parent, NULL, MMIO_FINDRIFF)) { // close the file mmioClose(hwav, 0); return(-1); } // descend to the WAVEfmt child.ckid = mmioFOURCC('f', 'm', 't', ' '); if (mmioDescend(hwav, &child, &parent, 0)) { // close the file mmioClose(hwav, 0); return(-1); } // now read the wave format information from file if (mmioRead(hwav, (char *)&wfmtx, sizeof(wfmtx)) != sizeof(wfmtx)) { // close file mmioClose(hwav, 0); return(-1); } // make sure that the data format is PCM if (wfmtx.wFormatTag != WAVE_FORMAT_PCM) { // close the file mmioClose(hwav, 0); return(-1); } // now ascend up one level, so we can access data chunk if (mmioAscend(hwav, &child, 0)) { // close file mmioClose(hwav, 0); return(-1); } // descend to the data chunk child.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(hwav, &child, &parent, MMIO_FINDCHUNK)) { // close file mmioClose(hwav, 0); return(-1); } // finally!!!! now all we have to do is read the data in and // set up the directsound buffer // allocate the memory to load sound data snd_buffer = (UCHAR *)malloc(child.cksize); // read the wave data mmioRead(hwav, (char *)snd_buffer, child.cksize); // close the file mmioClose(hwav, 0); // set rate and size in data structure sound_fx[sound_id].rate = wfmtx.nSamplesPerSec; sound_fx[sound_id].size = child.cksize; sound_fx[sound_id].state = SOUND_LOADED; // set up the format data structure memset(&pcmwf, 0, sizeof(WAVEFORMATEX)); pcmwf.wFormatTag = WAVE_FORMAT_PCM; // pulse code modulation pcmwf.nChannels = 1; // mono pcmwf.nSamplesPerSec = 11025; // always this rate pcmwf.nBlockAlign = 1; pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign; pcmwf.wBitsPerSample = 8; pcmwf.cbSize = 0; // prepare to create sounds buffer dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = control_flags | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE; dsbd.dwBufferBytes = child.cksize; dsbd.lpwfxFormat = &pcmwf; // create the sound buffer if (FAILED(lpds->CreateSoundBuffer(&dsbd,&sound_fx[sound_id].dsbuffer,NULL))) { // release memory free(snd_buffer); return(-1); } // copy data into sound buffer if (FAILED(sound_fx[sound_id].dsbuffer->Lock(0, child.cksize, (void **) &audio_ptr_1, &audio_length_1, (void **)&audio_ptr_2, &audio_length_2, DSBLOCK_FROMWRITECURSOR))) return(0); // copy first section of circular buffer memcpy(audio_ptr_1, snd_buffer, audio_length_1); // copy last section of circular buffer memcpy(audio_ptr_2, (snd_buffer+audio_length_1),audio_length_2); // unlock the buffer if (FAILED(sound_fx[sound_id].dsbuffer->Unlock(audio_ptr_1, audio_length_1, audio_ptr_2, audio_length_2))) return(0); // release the temp buffer free(snd_buffer); return(sound_id); }
/* This function will open a wave input file and prepare it for reading, * so the data can be easily * read with WaveReadFile. Returns 0 if successful, the error code if not. * pszFileName - Input filename to load. * phmmioIn - Pointer to handle which will be used * for further mmio routines. * ppwfxInfo - Ptr to ptr to WaveFormatEx structure * with all info about the file. * */ int WaveOpenFile( TCHAR*pszFileName, // (IN) HMMIO *phmmioIn, // (OUT) WAVEFORMATEX **ppwfxInfo, // (OUT) MMCKINFO *pckInRIFF // (OUT) ) { HMMIO hmmioIn; MMCKINFO ckIn; // chunk info. for general use. PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. WORD cbExtraAlloc; // Extra bytes for waveformatex int nError; // Return value. // Initialization... *ppwfxInfo = NULL; nError = 0; hmmioIn = NULL; if ((hmmioIn = mmioOpen(pszFileName, NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL) { nError = ER_CANNOTOPEN; goto ERROR_READING_WAVE; } if ((nError = (int)mmioDescend(hmmioIn, pckInRIFF, NULL, 0)) != 0) { goto ERROR_READING_WAVE; } if ((pckInRIFF->ckid != FOURCC_RIFF) || (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E'))) { nError = ER_NOTWAVEFILE; goto ERROR_READING_WAVE; } /* Search the input file for for the 'fmt ' chunk. */ ckIn.ckid = mmioFOURCC('f', 'm', 't', ' '); if ((nError = (int)mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK)) != 0) { goto ERROR_READING_WAVE; } /* Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>; * if there are extra parameters at the end, we'll ignore them */ if (ckIn.cksize < (long) sizeof(PCMWAVEFORMAT)) { nError = ER_NOTWAVEFILE; goto ERROR_READING_WAVE; } /* Read the 'fmt ' chunk into <pcmWaveFormat>.*/ if (mmioRead(hmmioIn, (HPSTR) &pcmWaveFormat, (long) sizeof(pcmWaveFormat)) != (long) sizeof(pcmWaveFormat)) { nError = ER_CANNOTREAD; goto ERROR_READING_WAVE; } // Ok, allocate the waveformatex, but if its not pcm // format, read the next word, and thats how many extra // bytes to allocate. if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM) cbExtraAlloc = 0; else { // Read in length of extra bytes. if (mmioRead(hmmioIn, (LPTSTR) &cbExtraAlloc, (long) sizeof(cbExtraAlloc)) != (long) sizeof(cbExtraAlloc)) { nError = ER_CANNOTREAD; goto ERROR_READING_WAVE; } } // Ok, now allocate that waveformatex structure. if ((*ppwfxInfo = GlobalAlloc(GMEM_FIXED, sizeof(WAVEFORMATEX)+cbExtraAlloc)) == NULL) { nError = ER_MEM; goto ERROR_READING_WAVE; } // Copy the bytes from the pcm structure to the waveformatex structure memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat)); (*ppwfxInfo)->cbSize = cbExtraAlloc; // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. if (cbExtraAlloc != 0) { if (mmioRead(hmmioIn, (LPTSTR) (((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(cbExtraAlloc)), (long) (cbExtraAlloc)) != (long) (cbExtraAlloc)) { nError = ER_NOTWAVEFILE; goto ERROR_READING_WAVE; } } /* Ascend the input file out of the 'fmt ' chunk. */ if ((nError = mmioAscend(hmmioIn, &ckIn, 0)) != 0) { goto ERROR_READING_WAVE; } goto TEMPCLEANUP; ERROR_READING_WAVE: if (*ppwfxInfo != NULL) { GlobalFree(*ppwfxInfo); *ppwfxInfo = NULL; } if (hmmioIn != NULL) { mmioClose(hmmioIn, 0); hmmioIn = NULL; } TEMPCLEANUP: *phmmioIn = hmmioIn; return(nError); }
//************************************************************************ BOOL CDirSnd::LoadWaveResource(LPSTR lpSound, HINSTANCE hInstance, BOOL b3D) // lpSound is a resource name //************************************************************************ { HGLOBAL hWave; LPTR lpWave; PCMWAVEFORMAT pcm; HMMIO hio; MMCKINFO RiffChunk; MMCKINFO FmtChunk; MMCKINFO DataChunk; HRESULT hr; MMRESULT Res; MMIOINFO Info; long lRead; WAVEFORMATEX Format; DSBUFFERDESC BuffDesc; BYTE *pData1; BYTE *pData2; DWORD dwBytes1; DWORD dwBytes2; Init( GetApp()->GetMainWnd() ); if ( !m_pDirectSound ) return NO; if ( !hInstance ) return NO; // Find the resource if ( !(hWave = (HGLOBAL)FindResource( hInstance, lpSound, "WAVE" )) ) return NO; // Load the resource if ( !(hWave = LoadResource( hInstance, (HRSRC)hWave )) ) return( NO ); // Lock it if ( !(lpWave = (LPTR)LockResource( hWave )) ) { FreeResource( hWave ); return NO; } // Set up mmio Info structure for opening memory for mmio memset(&Info, 0, sizeof(MMIOINFO)); Info.pchBuffer = (LPSTR)lpWave; Info.fccIOProc = FOURCC_MEM; Info.cchBuffer = SizeofResource(hInstance, (HRSRC)hWave); Info.adwInfo[0] = 0; // Open memory for mmio hio = mmioOpen(NULL, &Info, MMIO_READ); if (!hio) return 0; // Descened into the WAVE section RiffChunk.ckid = FOURCC_RIFF; RiffChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E' ); Res = mmioDescend(hio, &RiffChunk, NULL, MMIO_FINDRIFF); if (Res != 0) goto ERROR_READING_WAVE; // Descend into the fmt chunk FmtChunk.ckid = mmioFOURCC('f', 'm', 't', ' '); Res = mmioDescend(hio, &FmtChunk, &RiffChunk, MMIO_FINDCHUNK); if (Res != 0) goto ERROR_READING_WAVE; // Read the 'fmt ' chunk into <pcmWaveFormat> if (mmioRead(hio, (HPSTR) &pcm, (long)sizeof(pcm)) != (long) sizeof(pcm)) goto ERROR_READING_WAVE; DataChunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); Res = mmioDescend(hio, &DataChunk, &RiffChunk, MMIO_FINDCHUNK); if (Res != 0) goto ERROR_READING_WAVE; // Set the wave format memset(&Format, 0, sizeof(WAVEFORMATEX)); Format.wFormatTag = pcm.wf.wFormatTag; Format.nChannels = pcm.wf.nChannels; Format.nSamplesPerSec = pcm.wf.nSamplesPerSec; Format.nAvgBytesPerSec = pcm.wf.nAvgBytesPerSec; Format.nBlockAlign = pcm.wf.nBlockAlign; Format.wBitsPerSample = pcm.wBitsPerSample; // Set up the sound buffer description memset(&BuffDesc, 0, sizeof(BuffDesc)); BuffDesc.dwSize = sizeof(DSBUFFERDESC); if (b3D) BuffDesc.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_CTRL3D; else BuffDesc.dwFlags = DSBCAPS_CTRLDEFAULT; BuffDesc.dwBufferBytes = DataChunk.cksize; BuffDesc.lpwfxFormat = &Format; // Create the buffer hr = m_pDirectSound->CreateSoundBuffer( &BuffDesc, &m_pBuffer, NULL); if (hr != DS_OK) { goto ERROR_READING_WAVE; } if (b3D) { hr = m_pBuffer->QueryInterface(IID_IDirectSound3DBuffer, (void **)&m_p3dBuff); //hr = m_pBuffer->QueryInterface(IID_IMAPISession, (void **)&m_p3dBuff); if (SUCCEEDED(hr)) { // Set 3D parameters of this sound. hr = m_p3dBuff->SetPosition(D3DVAL(0), D3DVAL(0), D3DVAL(0), DS3D_IMMEDIATE); } } // Lock the buffer so we can read into it hr = m_pBuffer->Lock(0, DataChunk.cksize, &pData1, &dwBytes1, &pData2, &dwBytes2, 0); // If we got DSERR_BUFFERLOST, restore and retry lock. if (DSERR_BUFFERLOST == hr) { m_pBuffer->Restore(); hr = m_pBuffer->Lock(0, DataChunk.cksize, &pData1, &dwBytes1, &pData2, &dwBytes2, 0); } // Read the data lRead = mmioRead(hio, (HPSTR)pData1, dwBytes1); if (pData2 != NULL) lRead = mmioRead(hio, (HPSTR)pData2, dwBytes2); // Release the data back to DirectSound. hr = m_pBuffer->Unlock(pData1, dwBytes1, pData2, dwBytes2); ERROR_READING_WAVE: mmioClose(hio, 0); return YES; }
BOOL MCIAVI_GetInfo(WINE_MCIAVI* wma) { MMCKINFO ckMainRIFF; MMCKINFO mmckHead; MMCKINFO mmckList; MMCKINFO mmckInfo; AVIStreamHeader strh; struct AviListBuild alb; DWORD stream_n; if (mmioDescend(wma->hFile, &ckMainRIFF, NULL, 0) != 0) { WARN("Can't find 'RIFF' chunk\n"); return FALSE; } if ((ckMainRIFF.ckid != FOURCC_RIFF) || (ckMainRIFF.fccType != formtypeAVI)) { WARN("Can't find 'AVI ' chunk\n"); return FALSE; } mmckHead.fccType = listtypeAVIHEADER; if (mmioDescend(wma->hFile, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) { WARN("Can't find 'hdrl' list\n"); return FALSE; } mmckInfo.ckid = ckidAVIMAINHDR; if (mmioDescend(wma->hFile, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) { WARN("Can't find 'avih' chunk\n"); return FALSE; } mmioRead(wma->hFile, (LPSTR)&wma->mah, sizeof(wma->mah)); TRACE("mah.dwMicroSecPerFrame=%d\n", wma->mah.dwMicroSecPerFrame); TRACE("mah.dwMaxBytesPerSec=%d\n", wma->mah.dwMaxBytesPerSec); TRACE("mah.dwPaddingGranularity=%d\n", wma->mah.dwPaddingGranularity); TRACE("mah.dwFlags=%d\n", wma->mah.dwFlags); TRACE("mah.dwTotalFrames=%d\n", wma->mah.dwTotalFrames); TRACE("mah.dwInitialFrames=%d\n", wma->mah.dwInitialFrames); TRACE("mah.dwStreams=%d\n", wma->mah.dwStreams); TRACE("mah.dwSuggestedBufferSize=%d\n", wma->mah.dwSuggestedBufferSize); TRACE("mah.dwWidth=%d\n", wma->mah.dwWidth); TRACE("mah.dwHeight=%d\n", wma->mah.dwHeight); mmioAscend(wma->hFile, &mmckInfo, 0); TRACE("Start of streams\n"); wma->video_stream_n = 0; wma->audio_stream_n = 0; for (stream_n = 0; stream_n < wma->mah.dwStreams; stream_n++) { MMCKINFO mmckStream; mmckList.fccType = listtypeSTREAMHEADER; if (mmioDescend(wma->hFile, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) break; mmckStream.ckid = ckidSTREAMHEADER; if (mmioDescend(wma->hFile, &mmckStream, &mmckList, MMIO_FINDCHUNK) != 0) { WARN("Can't find 'strh' chunk\n"); continue; } mmioRead(wma->hFile, (LPSTR)&strh, sizeof(strh)); TRACE("Stream #%d fccType %4.4s\n", stream_n, (LPSTR)&strh.fccType); if (strh.fccType == streamtypeVIDEO) { TRACE("found video stream\n"); if (wma->inbih) WARN("ignoring another video stream\n"); else { wma->ash_audio = strh; if (!MCIAVI_GetInfoVideo(wma, &mmckList, &mmckStream)) return FALSE; wma->video_stream_n = stream_n; } } else if (strh.fccType == streamtypeAUDIO) { TRACE("found audio stream\n"); if (wma->lpWaveFormat) WARN("ignoring another audio stream\n"); else { wma->ash_video = strh; if (!MCIAVI_GetInfoAudio(wma, &mmckList, &mmckStream)) return FALSE; wma->audio_stream_n = stream_n; } } else TRACE("Unsupported stream type %4.4s\n", (LPSTR)&strh.fccType); mmioAscend(wma->hFile, &mmckList, 0); } TRACE("End of streams\n"); mmioAscend(wma->hFile, &mmckHead, 0); /* no need to read optional JUNK chunk */ mmckList.fccType = listtypeAVIMOVIE; if (mmioDescend(wma->hFile, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) { WARN("Can't find 'movi' list\n"); return FALSE; } wma->dwPlayableVideoFrames = wma->mah.dwTotalFrames; wma->lpVideoIndex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wma->dwPlayableVideoFrames * sizeof(struct MMIOPos)); if (!wma->lpVideoIndex) { WARN("Can't alloc video index array\n"); return FALSE; } wma->dwPlayableAudioBlocks = 0; wma->lpAudioIndex = NULL; alb.numAudioBlocks = alb.numVideoFrames = 0; alb.inVideoSize = alb.inAudioSize = 0; alb.numAudioAllocated = 0; while (mmioDescend(wma->hFile, &mmckInfo, &mmckList, 0) == 0) { if (mmckInfo.fccType == listtypeAVIRECORD) { MMCKINFO tmp; while (mmioDescend(wma->hFile, &tmp, &mmckInfo, 0) == 0) { MCIAVI_AddFrame(wma, &tmp, &alb); mmioAscend(wma->hFile, &tmp, 0); } } else { MCIAVI_AddFrame(wma, &mmckInfo, &alb); } mmioAscend(wma->hFile, &mmckInfo, 0); } if (alb.numVideoFrames != wma->dwPlayableVideoFrames) { WARN("Found %d video frames (/%d), reducing playable frames\n", alb.numVideoFrames, wma->dwPlayableVideoFrames); wma->dwPlayableVideoFrames = alb.numVideoFrames; } wma->dwPlayableAudioBlocks = alb.numAudioBlocks; if (alb.inVideoSize > wma->ash_video.dwSuggestedBufferSize) { WARN("inVideoSize=%d suggestedSize=%d\n", alb.inVideoSize, wma->ash_video.dwSuggestedBufferSize); wma->ash_video.dwSuggestedBufferSize = alb.inVideoSize; } if (alb.inAudioSize > wma->ash_audio.dwSuggestedBufferSize) { WARN("inAudioSize=%d suggestedSize=%d\n", alb.inAudioSize, wma->ash_audio.dwSuggestedBufferSize); wma->ash_audio.dwSuggestedBufferSize = alb.inAudioSize; } wma->indata = HeapAlloc(GetProcessHeap(), 0, wma->ash_video.dwSuggestedBufferSize); if (!wma->indata) { WARN("Can't alloc input buffer\n"); return FALSE; } return TRUE; }
/** MMIOストリームから読み込み * * @author SAM (T&GG, Org.)<*****@*****.**> * @date 2004/01/21 2:36:59 * Copyright (C) 2001,2002,2003,2004 SAM (T&GG, Org.). All rights reserved. */ HRslt WavFile::readMMIO() { MMCKINFO ckin; // chunk info. for general use. PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in. wfx_ = NULL; if(mmioDescend(hmmio_, &ckriff_, NULL, 0)) return DXTRACE_ERR(TEXT("mmioDescend"), E_FAIL); // Check to make sure this is a valid wave file if( (ckriff_.ckid != FOURCC_RIFF) || (ckriff_.fccType != mmioFOURCC('W','A','V','E') ) ) return DXTRACE_ERR( TEXT("mmioFOURCC"), E_FAIL ); // Search the input file for for the 'fmt ' chunk. ckin.ckid = mmioFOURCC('f','m','t',' '); if(mmioDescend(hmmio_, &ckin, &ckriff_, MMIO_FINDCHUNK) ) return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL ); // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>; // if there are extra parameters at the end, we'll ignore them if(ckin.cksize < sizeof(PCMWAVEFORMAT)) return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL ); // Read the 'fmt ' chunk into <pcmWaveFormat>. if( mmioRead( hmmio_, (HPSTR) &pcmWaveFormat, sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) ) return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL ); // Allocate the waveformatex, but if its not pcm format, read the next // word, and thats how many extra bytes to allocate. if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM ) { wfx_ = reinterpret_cast<WAVEFORMATEX *>(malloc( sizeof(WAVEFORMATEX) )); if(!wfx_) return DXTRACE_ERR( TEXT("wfx_"), E_OUTOFMEMORY ); // Copy the bytes from the pcm structure to the waveformatex structure memcpy( wfx_, &pcmWaveFormat, sizeof(pcmWaveFormat) ); wfx_->cbSize = 0; } else { // Read in length of extra bytes. WORD cbExtraBytes = 0L; if( mmioRead( hmmio_, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) ) return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL ); wfx_ = reinterpret_cast<WAVEFORMATEX *>(malloc( sizeof(WAVEFORMATEX) + cbExtraBytes )); if(!wfx_) return DXTRACE_ERR( TEXT("new"), E_OUTOFMEMORY ); // Copy the bytes from the pcm structure to the waveformatex structure memcpy( wfx_, &pcmWaveFormat, sizeof(pcmWaveFormat) ); wfx_->cbSize = cbExtraBytes; // Now, read those extra bytes into the structure, if cbExtraAlloc != 0. if( mmioRead( hmmio_, (CHAR*)(((BYTE*)&(wfx_->cbSize))+sizeof(WORD)), cbExtraBytes ) != cbExtraBytes ) { SAFE_FREE( wfx_ ); return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL ); } } // Ascend the input file out of the 'fmt ' chunk. if( 0 != mmioAscend( hmmio_, &ckin, 0 ) ) { SAFE_FREE( wfx_ ); return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL ); } return S_OK; }
static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr) { MMCKINFO ckMainRIFF; MMCKINFO mmckHead; MMCKINFO mmckList; MMCKINFO mmckInfo; DWORD numFrame; DWORD insize; if (mmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) { WARN("Can't find 'RIFF' chunk\n"); return FALSE; } if ((ckMainRIFF.ckid != FOURCC_RIFF) || (ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) { WARN("Can't find 'AVI ' chunk\n"); return FALSE; } mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l'); if (mmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) { WARN("Can't find 'hdrl' list\n"); return FALSE; } mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h'); if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) { WARN("Can't find 'avih' chunk\n"); return FALSE; } mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah)); TRACE("mah.dwMicroSecPerFrame=%d\n", infoPtr->mah.dwMicroSecPerFrame); TRACE("mah.dwMaxBytesPerSec=%d\n", infoPtr->mah.dwMaxBytesPerSec); TRACE("mah.dwPaddingGranularity=%d\n", infoPtr->mah.dwPaddingGranularity); TRACE("mah.dwFlags=%d\n", infoPtr->mah.dwFlags); TRACE("mah.dwTotalFrames=%d\n", infoPtr->mah.dwTotalFrames); TRACE("mah.dwInitialFrames=%d\n", infoPtr->mah.dwInitialFrames); TRACE("mah.dwStreams=%d\n", infoPtr->mah.dwStreams); TRACE("mah.dwSuggestedBufferSize=%d\n", infoPtr->mah.dwSuggestedBufferSize); TRACE("mah.dwWidth=%d\n", infoPtr->mah.dwWidth); TRACE("mah.dwHeight=%d\n", infoPtr->mah.dwHeight); mmioAscend(infoPtr->hMMio, &mmckInfo, 0); mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) { WARN("Can't find 'strl' list\n"); return FALSE; } mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h'); if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { WARN("Can't find 'strh' chunk\n"); return FALSE; } mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash)); TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccType)), HIBYTE(LOWORD(infoPtr->ash.fccType)), LOBYTE(HIWORD(infoPtr->ash.fccType)), HIBYTE(HIWORD(infoPtr->ash.fccType))); TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccHandler)), HIBYTE(LOWORD(infoPtr->ash.fccHandler)), LOBYTE(HIWORD(infoPtr->ash.fccHandler)), HIBYTE(HIWORD(infoPtr->ash.fccHandler))); TRACE("ash.dwFlags=%d\n", infoPtr->ash.dwFlags); TRACE("ash.wPriority=%d\n", infoPtr->ash.wPriority); TRACE("ash.wLanguage=%d\n", infoPtr->ash.wLanguage); TRACE("ash.dwInitialFrames=%d\n", infoPtr->ash.dwInitialFrames); TRACE("ash.dwScale=%d\n", infoPtr->ash.dwScale); TRACE("ash.dwRate=%d\n", infoPtr->ash.dwRate); TRACE("ash.dwStart=%d\n", infoPtr->ash.dwStart); TRACE("ash.dwLength=%d\n", infoPtr->ash.dwLength); TRACE("ash.dwSuggestedBufferSize=%d\n", infoPtr->ash.dwSuggestedBufferSize); TRACE("ash.dwQuality=%d\n", infoPtr->ash.dwQuality); TRACE("ash.dwSampleSize=%d\n", infoPtr->ash.dwSampleSize); TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left, infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right); mmioAscend(infoPtr->hMMio, &mmckInfo, 0); mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f'); if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { WARN("Can't find 'strh' chunk\n"); return FALSE; } infoPtr->inbih = Alloc(mmckInfo.cksize); if (!infoPtr->inbih) { WARN("Can't alloc input BIH\n"); return FALSE; } mmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize); TRACE("bih.biSize=%d\n", infoPtr->inbih->biSize); TRACE("bih.biWidth=%d\n", infoPtr->inbih->biWidth); TRACE("bih.biHeight=%d\n", infoPtr->inbih->biHeight); TRACE("bih.biPlanes=%d\n", infoPtr->inbih->biPlanes); TRACE("bih.biBitCount=%d\n", infoPtr->inbih->biBitCount); TRACE("bih.biCompression=%d\n", infoPtr->inbih->biCompression); TRACE("bih.biSizeImage=%d\n", infoPtr->inbih->biSizeImage); TRACE("bih.biXPelsPerMeter=%d\n", infoPtr->inbih->biXPelsPerMeter); TRACE("bih.biYPelsPerMeter=%d\n", infoPtr->inbih->biYPelsPerMeter); TRACE("bih.biClrUsed=%d\n", infoPtr->inbih->biClrUsed); TRACE("bih.biClrImportant=%d\n", infoPtr->inbih->biClrImportant); mmioAscend(infoPtr->hMMio, &mmckInfo, 0); mmioAscend(infoPtr->hMMio, &mmckList, 0); #if 0 /* an AVI has 0 or 1 video stream, and to be animated should not contain * an audio stream, so only one strl is allowed */ mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) { WARN("There should be a single 'strl' list\n"); return FALSE; } #endif mmioAscend(infoPtr->hMMio, &mmckHead, 0); /* no need to read optional JUNK chunk */ mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i'); if (mmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) { WARN("Can't find 'movi' list\n"); return FALSE; } /* FIXME: should handle the 'rec ' LIST when present */ infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD)); if (!infoPtr->lpIndex) return FALSE; numFrame = insize = 0; while (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 && numFrame < infoPtr->mah.dwTotalFrames) { infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset; if (insize < mmckInfo.cksize) insize = mmckInfo.cksize; numFrame++; mmioAscend(infoPtr->hMMio, &mmckInfo, 0); } if (numFrame != infoPtr->mah.dwTotalFrames) { WARN("Found %d frames (/%d)\n", numFrame, infoPtr->mah.dwTotalFrames); return FALSE; } if (insize > infoPtr->ash.dwSuggestedBufferSize) { WARN("insize=%d suggestedSize=%d\n", insize, infoPtr->ash.dwSuggestedBufferSize); infoPtr->ash.dwSuggestedBufferSize = insize; } infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize); if (!infoPtr->indata) return FALSE; return TRUE; }
BOOL CWaveFile::PrepareWaveFile(LPCTSTR lpszFileName) { if(lpszFileName == NULL || *lpszFileName == _T('\0')) { _stprintf(m_szErrorMsg, _T("Empty file name")); return FALSE; } //The previous opened file is not closed yet if(m_hWaveFile != NULL) { _stprintf(m_szErrorMsg, _T("The previous open file [%s] is not closed yet"), m_szFileName); return FALSE; } _tcscpy(m_szFileName, lpszFileName); //Open wave file m_hWaveFile = mmioOpen(m_szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF); if(m_hWaveFile == NULL) { _stprintf(m_szErrorMsg, _T("mmioOpen file %s failed"), m_szFileName); return FALSE; } //Chunk info structures MMCKINFO ckInfoParent, ckInfo; MMRESULT mmResult = 0; char* fmtBuffer = NULL; LONG lVar; BOOL bRet = FALSE; do { //Find riff wave ckInfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); mmResult = mmioDescend(m_hWaveFile, &ckInfoParent, NULL, MMIO_FINDRIFF); if(mmResult != MMSYSERR_NOERROR) { _stprintf(m_szErrorMsg, _T("mmioDescend find riff wave failed")); break; } //Find chunk "fmt " ckInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); mmResult = mmioDescend(m_hWaveFile, &ckInfo, &ckInfoParent, MMIO_FINDCHUNK); if(mmResult != MMSYSERR_NOERROR) { _stprintf(m_szErrorMsg, _T("mmioDescend find chunk 'fmt ' failed")); break; } //create 'fmt ' buffer fmtBuffer = new char[ckInfo.cksize]; //Read 'fmt ' content lVar = mmioRead(m_hWaveFile, (HPSTR)fmtBuffer, ckInfo.cksize); if( (DWORD)lVar != ckInfo.cksize ) { _stprintf(m_szErrorMsg, _T("mmioRead read 'fmt ' content failed. fmtSize=%d, read=%d"), ckInfo.cksize, lVar); break; } //remember the fmt m_lpWaveFormat = (WAVEFORMATEX*)fmtBuffer; m_dwWaveFormatSize = ckInfo.cksize; //leave chunk 'fmt ' mmResult = mmioAscend(m_hWaveFile, &ckInfo, 0); if(mmResult != MMSYSERR_NOERROR) { _stprintf(m_szErrorMsg, _T("mmioAscend leave 'fmt ' chunk failed. mmResult=%u"), mmResult); break; } //Find chunk 'data' ckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); mmResult = mmioDescend(m_hWaveFile, &ckInfo, &ckInfoParent, MMIO_FINDCHUNK); if(mmResult != MMSYSERR_NOERROR) { _stprintf(m_szErrorMsg, _T("mmioDescend find 'data' chunk failed. mmResult=%u"), mmResult); break; } //remember the data chunk info m_ckInfoData = ckInfo; m_dwDataReadCount = 0; //Seek the file position to the chunk 'data' start lVar = mmioSeek(m_hWaveFile, m_ckInfoData.dwDataOffset, SEEK_SET); if((DWORD)lVar != m_ckInfoData.dwDataOffset) { _stprintf(m_szErrorMsg, _T("mmioSeek to chunk 'data' failed. position=%d"), lVar); break; } //everything is ok bRet = TRUE; } while (FALSE); if(!bRet) { if(fmtBuffer != NULL) { delete[] fmtBuffer; fmtBuffer = NULL; } m_lpWaveFormat = NULL; } return bRet; }
/************************************************************************** * mmioRead [MMSYSTEM.1212] */ LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch) { return mmioRead(HMMIO_32(hmmio), pch, cch); }
// Open BOOL WaveFile::Open (LPSTR pszFilename) { WORD cbExtra = 0; DOUT ("WaveFile::Open\n\r"); BOOL fRtn = SUCCESS; // assume success // Open the requested file if ((m_hmmio = mmioOpen (pszFilename, NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL) { m_mmr = MMIOERR_CANNOTOPEN; goto OPEN_ERROR; } // Descend into initial chunk ('RIFF') if (m_mmr = mmioDescend (m_hmmio, &m_mmckiRiff, NULL, 0)) { goto OPEN_ERROR; } // Validate that it's a WAVE file if ((m_mmckiRiff.ckid != FOURCC_RIFF) || (m_mmckiRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) { m_mmr = MMIOERR_INVALIDFILE; goto OPEN_ERROR; } // Find format chunk ('fmt '), allocate and fill WAVEFORMATEX structure m_mmckiFmt.ckid = mmioFOURCC('f', 'm', 't', ' '); if (m_mmr = mmioDescend (m_hmmio, &m_mmckiFmt, &m_mmckiRiff, MMIO_FINDCHUNK)) { goto OPEN_ERROR; } // Read the format chunk into temporary structure PCMWAVEFORMAT pcmwf; if (mmioRead (m_hmmio, (CHAR *) &pcmwf, sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT)) { m_mmr = MMIOERR_CANNOTREAD; goto OPEN_ERROR; } // If format is not PCM, then there are extra bytes appended to WAVEFORMATEX if (pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM) { // Read WORD specifying number of extra bytes if (mmioRead (m_hmmio, (LPSTR) &cbExtra, sizeof (cbExtra)) != sizeof(cbExtra)) { m_mmr = MMIOERR_CANNOTREAD; goto OPEN_ERROR; } } // Allocate memory for WAVEFORMATEX structure + extra bytes // UNDONE: GMEM_FIXED???? use malloc? if (m_pwfmt = (WAVEFORMATEX *) GlobalAlloc (GMEM_FIXED, sizeof(WAVEFORMATEX)+cbExtra)) { // Copy bytes from temporary format structure memcpy (m_pwfmt, &pcmwf, sizeof(pcmwf)); m_pwfmt->cbSize = cbExtra; // Read those extra bytes, append to WAVEFORMATEX structure if (cbExtra != 0) { if ((m_mmr = mmioRead (m_hmmio, (LPSTR) ((BYTE *)(m_pwfmt) + sizeof (WAVEFORMATEX)), cbExtra)) != cbExtra) { // Error reading extra bytes m_mmr = MMIOERR_CANNOTREAD; goto OPEN_ERROR; } } } else { // Error allocating memory m_mmr = MMIOERR_OUTOFMEMORY; goto OPEN_ERROR; } // Init some member data from format chunk m_nBlockAlign = m_pwfmt->nBlockAlign; m_nAvgDataRate = m_pwfmt->nAvgBytesPerSec; // Ascend out of format chunk if (m_mmr = mmioAscend (m_hmmio, &m_mmckiFmt, 0)) { goto OPEN_ERROR; } // Cue for streaming Cue (); // Init some member data from data chunk // Note cast to __int64 to prevent rollover error in calculation m_nDataSize = m_mmckiData.cksize; m_nDuration = (UINT)(((__int64) m_nDataSize * 1000) / m_nAvgDataRate); // Successful open! goto OPEN_DONE; OPEN_ERROR: // Handle all errors here fRtn = FALSE; if (m_hmmio) { // Close file mmioClose (m_hmmio, 0); m_hmmio = NULL; } if (m_pwfmt) { // UNDONE: Change here if using malloc // Free memory GlobalFree (m_pwfmt); m_pwfmt = NULL; } OPEN_DONE: return (fRtn); }
// Read // // Returns number of bytes actually read. // // Returns -1 if there is nothing more to be read. This function can return 0, since // sometimes the amount of bytes requested is too small for the ACM decompression to // locate a suitable block int WaveFile::Read(BYTE *pbDest, UINT cbSize, int service) { unsigned char *dest_buf=NULL, *uncompressed_wave_data; int rc, uncompressed_bytes_written; unsigned int src_bytes_used, convert_len, num_bytes_desired=0, num_bytes_read; // nprintf(("Alan","Reqeusted: %d\n", cbSize)); if ( service ) { uncompressed_wave_data = Wavedata_service_buffer; } else { uncompressed_wave_data = Wavedata_load_buffer; } switch ( m_wave_format ) { case WAVE_FORMAT_PCM: num_bytes_desired = cbSize; dest_buf = pbDest; break; case WAVE_FORMAT_ADPCM: if ( !m_hStream_open ) { if ( !ACM_stream_open(m_pwfmt_original, &m_wfxDest, (void**)&m_hStream), m_bits_per_sample_uncompressed ) { m_hStream_open = 1; } else { Int3(); } } num_bytes_desired = cbSize; if ( service ) { dest_buf = Compressed_service_buffer; } else { dest_buf = Compressed_buffer; } if ( num_bytes_desired <= 0 ) { num_bytes_desired = 0; // nprintf(("Alan","No bytes required for ADPCM time interval\n")); } else { num_bytes_desired = ACM_query_source_size((void*)m_hStream, cbSize); // nprintf(("Alan","Num bytes desired: %d\n", num_bytes_desired)); } break; default: nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n")); Int3(); break; } // end switch num_bytes_read = 0; convert_len = 0; src_bytes_used = 0; // read data from disk if ( m_data_bytes_left <= 0 ) { num_bytes_read = 0; uncompressed_bytes_written = 0; return -1; } if ( m_data_bytes_left > 0 && num_bytes_desired > 0 ) { int actual_read; if ( num_bytes_desired <= (unsigned int)m_data_bytes_left ) { num_bytes_read = num_bytes_desired; } else { num_bytes_read = m_data_bytes_left; } actual_read = mmioRead( cfp, (char *)dest_buf, num_bytes_read ); if ( (actual_read <= 0) || (m_abort_next_read) ) { num_bytes_read = 0; uncompressed_bytes_written = 0; return -1; } if ( num_bytes_desired >= (unsigned int)m_data_bytes_left ) { m_abort_next_read = 1; } num_bytes_read = actual_read; } // convert data if necessary, to PCM if ( m_wave_format == WAVE_FORMAT_ADPCM ) { if ( num_bytes_read > 0 ) { rc = ACM_convert((void*)m_hStream, dest_buf, num_bytes_read, uncompressed_wave_data, BIGBUF_SIZE, &convert_len, &src_bytes_used); if ( rc == -1 ) { goto READ_ERROR; } if ( convert_len == 0 ) { Int3(); } } Assert(src_bytes_used <= num_bytes_read); if ( src_bytes_used < num_bytes_read ) { // seek back file pointer to reposition before unused source data mmioSeek(cfp, src_bytes_used - num_bytes_read, SEEK_CUR); } // Adjust number of bytes left m_data_bytes_left -= src_bytes_used; m_nBytesPlayed += src_bytes_used; uncompressed_bytes_written = convert_len; // Successful read, keep running total of number of data bytes read goto READ_DONE; } else { // Successful read, keep running total of number of data bytes read // Adjust number of bytes left m_data_bytes_left -= num_bytes_read; m_nBytesPlayed += num_bytes_read; uncompressed_bytes_written = num_bytes_read; goto READ_DONE; } READ_ERROR: num_bytes_read = 0; uncompressed_bytes_written = 0; READ_DONE: m_total_uncompressed_bytes_read += uncompressed_bytes_written; // nprintf(("Alan","Read: %d\n", uncompressed_bytes_written)); return (uncompressed_bytes_written); }
int main(int argc, char *argv[]) { // // initial seconds count, set to zero. int seconds = 0; // // Here we say who we are... cout << "WavMix Version 1.1 built " << __DATE__ << " " << __TIME__ << endl; cout << "Application mixes 44.1khz stereo wav files only." << endl; cout << endl; if (argc < 5) { // // cout << endl; cout << " Usage:" << endl; cout << " Provide two source filenames, a target file name, the number of seconds" << endl; cout << " you wish to mix, optional flag to just produce a sample mix, " << endl; cout << " This program REQUIRES MMPM/2 to be installed." << endl; cout << endl; cout << " This application mixes 44.1khz stereo wav files only. It will mix two" << endl; cout << " source wav files and create a target wav file. You set the amount of " << endl; cout << " overlap in seconds. WavMix will mix using the seconds of overlap. A " << endl; cout << " preview mode is provided. Since wave files of this type are extremely " << endl; cout << " large, it will produce a target wav file of just the overlap so you " << endl; cout << " may preview your mixdowns" << endl; cout << endl; cout << endl; cout << " Sample command line" << endl; cout << " [r:\\audio\\mixdown] wavmix track01.wav track02.wav output.wav 5 " << endl; cout << " Above line mixes track01.wav and track02.wav using 5 seconds " << endl; cout << " of overlap creating output.wav" << endl; cout << endl; cout << " [r:\\audio\\mixdown] wavmix track01.wav track02.wav output.wav 5 S" << endl; cout << " Above line mixes 5 seconds of audio from the end of track01.wav and the" << endl; cout << " start of track02.wav creating output.wav" << endl; cout << endl; cout << endl; cout << " Support questions or comments to [email protected]" << endl; cout << "Provide filename1 filename2 destinationfile secondtomix (Longcut)" << endl; return 1; } // // set the type of mix we are going to do. if this is true, we do a full mix, if its // false, we only will do a "sample" of the mix part. short longcut = TRUE; if (argc > 5) { if (strcmp(argv[5],"S")==0) { cout << "Output file will only be the overlap." << endl; longcut = FALSE; } } seconds= atoi(argv[4]); if (seconds == 0) { cout << " ERROR: You cannot set seconds-to-mix to 0. " << endl; return 5; } MMAUDIOHEADER mmAudioHeader,mmAudioHeader2; // // open file1 HMMIO hmmio = mmioOpen(argv[1],NULL,MMIO_READ | MMIO_ALLOCBUF); if (hmmio==0) { cout << "Failed to open file " << argv[1] << endl; return 1; } long BytesRead; int rc = mmioGetHeader(hmmio,(PVOID)&mmAudioHeader,sizeof(MMAUDIOHEADER),&BytesRead,NULL,NULL); if (rc) { cout << "Error on mmioGetHeader for file " << argv[1] << endl; } // // now open the second file HMMIO hmmio2 = mmioOpen(argv[2],NULL,MMIO_READ | MMIO_ALLOCBUF); if (hmmio2==0) { cout << "ERROR: Failed to open file " << argv[2] << endl; return 2; } rc = mmioGetHeader(hmmio2,(PVOID)&mmAudioHeader2,sizeof(MMAUDIOHEADER),&BytesRead,NULL,NULL); if (rc) { cout << "ERROR on mmioGetHeader 2 " << endl; return 3; } // // now we are going to create another wave file MMIOINFO mmioinfo; memset(&mmioinfo,'\0',sizeof(mmioinfo)); mmioinfo.ulTranslate = MMIO_TRANSLATEHEADER+MMIO_TRANSLATEDATA; mmioinfo.aulInfo[3] = MMIO_MEDIATYPE_AUDIO; mmioinfo.fccIOProc = mmioFOURCC('W','A','V','E'); HMMIO hmmioTo = mmioOpen(argv[3],&mmioinfo,MMIO_CREATE+MMIO_WRITE); if (!hmmioTo) { cout << "ERROR : Could not create file." << argv[3] << endl; return 1; } // here we calculate the OFFSET from the back of the file for the 5 second overlay long audiosize = 176400 * seconds; // seconds of audio long filesize1 = mmAudioHeader.mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes; long filesize2 = mmAudioHeader2.mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes; if (audiosize > filesize1) { cout << "ERROR, you cannot have a mix area that is larger than your source audio file. " << endl; return 1; } if (longcut != TRUE) { // // install the new file size in the buffer mmAudioHeader.mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes = audiosize; cout << "Total resulting file size is: " << audiosize << endl; } if (longcut == TRUE) { // // install the new file size in the buffer mmAudioHeader.mmXWAVHeader.XWAVHeaderInfo.ulAudioLengthInBytes = filesize1 + filesize2; cout << "Total resulting file size is: " << (filesize1 + filesize2) << endl; } // // here we calculate the seekto, not necessary really with longcut long seekto = filesize1 - audiosize; cout << "Attempting to mix " << seconds << " seconds " << endl; // // first we copy the begining of file 1 to destfile if (longcut==TRUE) { cout << "Copying " << seekto << " bytes" << endl; copyaudio(hmmio,hmmioTo,seekto); } // // now seek to the new location in file 1 LONG newPos = mmioSeek(hmmio,seekto,0); assert(newPos == seekto); // // allocate a buffer PSHORT pAudio = NULL; DosAllocMem((void **) &pAudio,audiosize,PAG_WRITE | PAG_COMMIT); // // now read the FIRST file BytesRead = mmioRead(hmmio,(PCHAR)pAudio,audiosize); assert(BytesRead == audiosize); // // now allocate the second buffer PSHORT pAudio2 = NULL; DosAllocMem((void **) &pAudio2,audiosize,PAG_WRITE | PAG_COMMIT); // // and read that in BytesRead = mmioRead(hmmio2,(PCHAR)pAudio2,audiosize); assert(BytesRead == audiosize); // // now ADD them together? long shortsize = audiosize/2; for (unsigned long index = 0; index < shortsize ; index++) { short part1 = *(pAudio+index); short part2 = *(pAudio2+index); short result = part1 + part2; *(pAudio+index) = result; // *(pAudio+index) = *(pAudio2+index) + *(pAudio+index); } // // build the header rc = mmioSetHeader(hmmioTo,&mmAudioHeader,sizeof(MMAUDIOHEADER),&BytesRead,0,0); if (rc) { cout << "Error in mmioSetHeader" << endl; return 1; } // // write the new file rc = mmioWrite(hmmioTo,(PCHAR)pAudio,audiosize); if (rc < 0) { cout << "ERROR during a write" << endl; } // // now, copy the rest of file 2 if (longcut == TRUE) { cout << "Copying " << filesize2 - audiosize << " bytes" << endl; copyaudio(hmmio2,hmmioTo,filesize2 - audiosize); } DosFreeMem(pAudio); DosFreeMem(pAudio2); mmioClose(hmmio,0); mmioClose(hmmio2,0); mmioClose(hmmioTo,0); cout << "Finished, output file created" << endl; }
TDDSDGenWave::TDDSDGenWave( TDDSD* OWner, const wstring& fname, bool is3D, bool useFX ) { FIsStream = false; FOwner = OWner; FUseFX = useFX; //サウンドカードが無いなら、何もしない if( ! FOwner->Initialized() ) return; HMMIO hm = mmioOpen((LPWSTR)fname.c_str(), NULL, MMIO_READ | MMIO_ALLOCBUF); if( hm == 0 ) { //PutDebugMessage(fname + 'が、見つかりません'); return; } //WAVEに入る MMCKINFO mckP; //親チャンクの情報 mckP.fccType = MakeFourCC('W','A','V','E'); if( (mmioDescend(hm, &mckP, NULL, MMIO_FINDRIFF)) != 0 ) { mmioClose(hm, 0); //PutDebugMessage(fname + 'は、WAVEファイルではありません'); return; } //fmtチャンクに入る MMCKINFO mckC; //子チャンクの情報 mckC.ckid = MakeFourCC('f','m','t',' '); if( mmioDescend(hm, &mckC, &mckP, MMIO_FINDCHUNK) != 0 ) { mmioClose(hm, 0); //PutDebugMessage(fname + 'には、fmtチャンクが有りません'); return; } //fmtチャンクを読み取る u32 fmtSize = mckC.cksize; if( mmioRead(hm, (HPSTR)&FWaveFormat, fmtSize) != fmtSize ) { mmioClose(hm, 0); //PutDebugMessage(fname + 'のfmtチャンクが不正です'); return; } //fmtチャンクを抜け、dataチャンクに入る mmioAscend(hm, &mckC, 0); mckC.ckid = MakeFourCC('d','a','t','a'); if( mmioDescend(hm, &mckC, &mckP, MMIO_FINDCHUNK) != 0 ) { mmioClose(hm, 0); //PutDebugMessage(fname + 'には、dataチャンクが有りません'); return; } u32 dataSize = mckC.cksize; //二次バッファの作成 DSBUFFERDESC dsbd; ZeroMemory(&dsbd, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); if( is3D ) dsbd.dwFlags = DSBCAPS_CTRLVOLUME + DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRL3D; else dsbd.dwFlags = DSBCAPS_CTRLPAN + DSBCAPS_CTRLVOLUME + DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN; if( FUseFX ) dsbd.dwFlags = DSBCAPS_CTRLPAN + DSBCAPS_CTRLVOLUME + DSBCAPS_CTRLFREQUENCY + DSBCAPS_CTRLFX; if( FOwner->FStickyFocus ) dsbd.dwFlags = dsbd.dwFlags | DSBCAPS_STICKYFOCUS; dsbd.dwBufferBytes = dataSize; dsbd.lpwfxFormat = &FWaveFormat; FLength = dataSize; IDirectSoundBuffer* dsb; FOwner->DSound()->CreateSoundBuffer(&dsbd, &dsb, NULL); dsb->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*)&FSoundBuffer); dsb->Release(); //二次バッファのロック LPVOID lpBuf1, lpBuf2; DWORD dwBuf1, dwBuf2; FSoundBuffer->Lock(0,dataSize, &lpBuf1, &dwBuf1, &lpBuf2, &dwBuf2, 0); //音データのロード(dataチャンクを読み取る) mmioRead(hm, (HPSTR)lpBuf1, dwBuf1); if( dwBuf2 != 0 ) { mmioRead(hm, (HPSTR)lpBuf2, dwBuf2); } FSoundBuffer->Unlock(lpBuf1,dwBuf1,lpBuf2,dwBuf2); FSoundBuffer->SetFrequency(FWaveFormat.nSamplesPerSec); mmioClose(hm, 0); }
size_t ogg_mmio_read(void* buf, size_t elsize, size_t elnem, void* mmfp) { STRHDL* hdl = (STRHDL*)mmfp; return mmioRead(hdl->cfp, (HPSTR)buf, elsize * elnem); }