newspeoplefor developersdocumentationdownloads

nwavfile.cc

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00002 //  nwavfile.cc
00003 //  (C) 2005 Radon Labs GmbH
00004 //------------------------------------------------------------------------------
00005 #include "audio3/nwavfile.h"
00006 #include "kernel/nfileserver2.h"
00007 #include "kernel/nfile.h"
00008 
00009 bool nWavFile::mmioProcInstalled = false;
00010 
00011 //------------------------------------------------------------------------------
00018 LRESULT CALLBACK
00019 mmioProc(LPSTR lpstr, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
00020 {
00021     MMIOINFO* lpMMIOInfo = (MMIOINFO*)lpstr;
00022 
00023     n_assert(0 != lpMMIOInfo);
00024     n_assert(mmioFOURCC('N','E','B','2') == lpMMIOInfo->fccIOProc);
00025     n_assert(mmioProc == lpMMIOInfo->pIOProc);
00026 
00027     switch (uMsg)
00028     {
00029         case MMIOM_OPEN:
00030             {
00031                 if (0 == (lpMMIOInfo->dwFlags & (MMIO_WRITE | MMIO_READWRITE)))
00032                 {
00033                     // strip the "X.NEB2+" prefix from the file
00034                     nString rawName((const char*)lParam1);
00035                     nString filename = rawName.ExtractRange(7, rawName.Length() - 7);
00036 
00037                     // open a Nebula2 file for reading
00038                     nFile* file = nFileServer2::Instance()->NewFileObject();
00039                     if (file->Open(filename, "rb"))
00040                     {
00041                         // store nebula file object in mmio struct
00042                         lpMMIOInfo->adwInfo[0] = (DWORD) file;
00043                         return MMSYSERR_NOERROR;
00044                     }
00045                     else
00046                     {
00047                         file->Release();
00048                     }
00049                 }
00050 
00051                 // fallthrough: some error occurred
00052                 return MMIOERR_CANNOTOPEN;
00053             }
00054 
00055         case MMIOM_CLOSE:
00056             {
00057                 nFile* file = (nFile*)lpMMIOInfo->adwInfo[0];
00058                 n_assert(0 != file);
00059 
00060                 file->Close();
00061                 file->Release();
00062                 lpMMIOInfo->adwInfo[0] = 0;
00063 
00064                 return 0;
00065             }
00066 
00067         case MMIOM_READ:
00068             {
00069                 nFile* file = (nFile*)lpMMIOInfo->adwInfo[0];
00070                 n_assert(0 != file && file->IsOpen());
00071 
00072                 int bytesRead = file->Read((HPSTR)lParam1, (LONG)lParam2);
00073                 lpMMIOInfo->lDiskOffset += bytesRead;
00074 
00075                 return bytesRead;
00076             }
00077 
00078         case MMIOM_SEEK:
00079             {
00080                 nFile* file = (nFile*)lpMMIOInfo->adwInfo[0];
00081                 n_assert(0 != file && file->IsOpen());
00082 
00083                 nFile::nSeekType seekType;
00084                 switch ((int)lParam2)
00085                 {
00086                     case SEEK_CUR: seekType = nFile::CURRENT; break;
00087                     case SEEK_END: seekType = nFile::END; break;
00088                     default:       seekType = nFile::START; break;
00089                 }
00090 
00091                 if (file->Seek((LONG)lParam1, seekType))
00092                 {
00093                     lpMMIOInfo->lDiskOffset = file->Tell();
00094                     return lpMMIOInfo->lDiskOffset;
00095                 }
00096                 else
00097                 {
00098                     return -1;
00099                 }
00100             }
00101 
00102         case MMIOM_WRITE:
00103         case MMIOM_WRITEFLUSH:
00104             // not supported
00105             return -1;
00106     }
00107 
00108     // message not recognized
00109     return 0;
00110 }
00111 
00112 //------------------------------------------------------------------------------
00115 nWavFile::nWavFile() :
00116     m_pwfx(0),
00117     m_hmmio(NULL),
00118     m_dwSize(0)
00119 {
00120     // install MMIO custom file routines?
00121     if (!mmioProcInstalled)
00122     {
00123         LPMMIOPROC p = mmioInstallIOProc(mmioFOURCC('N','E','B','2'), mmioProc, MMIO_INSTALLPROC);
00124         n_assert(p);
00125         mmioProcInstalled = true;
00126     }
00127 }
00128 
00129 //------------------------------------------------------------------------------
00132 nWavFile::~nWavFile()
00133 {
00134     if (this->IsOpen())
00135     {
00136         this->Close();
00137     }
00138 }
00139 
00140 //------------------------------------------------------------------------------
00143 bool
00144 nWavFile::Open(const nString& filename)
00145 {
00146     n_assert(!this->IsOpen());
00147     n_assert(filename.IsValid());
00148 
00149     // modify filename so that MMIO will invoke our custom file function
00150     nString mangledPath = nFileServer2::Instance()->ManglePath(filename);
00151     nString mmioFilename("X.NEB2+");
00152     mmioFilename.Append(mangledPath);
00153 
00154     // open the file
00155     this->m_hmmio = mmioOpen((LPSTR)mmioFilename.Get(), NULL, MMIO_ALLOCBUF | MMIO_READ);
00156     if (NULL == this->m_hmmio)
00157     {
00158         n_error("nWavFile::Open(): failed to open file '%s'!", filename.Get());
00159         return false;
00160     }
00161 
00162     // check if it's a wav file
00163     if (!this->ReadMMIO())
00164     {
00165         mmioClose(this->m_hmmio, 0);
00166         n_error("nWavFile::Open(): not a wav file (%s)!", filename.Get());
00167         return false;
00168     }
00169 
00170     // reset the file to the beginning of data
00171     this->Reset();
00172 
00173     // store size of file (valid after ResetFile())
00174     this->m_dwSize = this->m_ck.cksize;
00175 
00176     this->isOpen = true;
00177     return true;
00178 }
00179 
00180 //------------------------------------------------------------------------------
00183 void
00184 nWavFile::Close()
00185 {
00186     n_assert(this->IsOpen());
00187     n_assert(0 != this->m_hmmio);
00188 
00189     n_delete(this->m_pwfx);
00190     this->m_pwfx = 0;
00191 
00192     mmioClose(this->m_hmmio, 0);
00193     this->m_hmmio = 0;
00194     this->isOpen = false;
00195 }
00196 
00197 //------------------------------------------------------------------------------
00200 int
00201 nWavFile::GetSize() const
00202 {
00203     n_assert(this->IsOpen());
00204     return this->m_dwSize;
00205 }
00206 
00207 //------------------------------------------------------------------------------
00210 WAVEFORMATEX*
00211 nWavFile::GetFormat() const
00212 {
00213     return this->m_pwfx;
00214 }
00215 
00216 //------------------------------------------------------------------------------
00221 bool
00222 nWavFile::ReadMMIO()
00223 {
00224     n_assert(this->m_hmmio);
00225 
00226     MMCKINFO ckIn;
00227     PCMWAVEFORMAT pcmWaveFormat;
00228 
00229     this->m_pwfx = NULL;
00230 
00231     // read next chunk
00232     if (0 != mmioDescend(this->m_hmmio, &this->m_ckRiff, NULL, 0))
00233     {
00234         return false;
00235     }
00236 
00237     // check for valid wav file
00238     if ((this->m_ckRiff.ckid != FOURCC_RIFF) ||
00239         (this->m_ckRiff.fccType != mmioFOURCC('W','A','V','E')))
00240     {
00241         return false;
00242     }
00243 
00244     // search the fmt chunk
00245     ckIn.ckid = mmioFOURCC('f','m','t',' ');
00246     if (0 != mmioDescend(this->m_hmmio, &ckIn, &this->m_ckRiff, MMIO_FINDCHUNK))
00247     {
00248         return false;
00249     }
00250 
00251     // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
00252     // if there are extra parameters at the end, we'll ignore them
00253     if (ckIn.cksize < (LONG)sizeof(PCMWAVEFORMAT))
00254     {
00255         return false;
00256     }
00257 
00258     // read fmt chunk into pcmWaveFormat
00259     if (mmioRead(this->m_hmmio, (HPSTR)&pcmWaveFormat, sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat))
00260     {
00261         return false;
00262     }
00263 
00264     // Allocate the waveformatex, but if its not pcm format, read the next
00265     // word, and thats how many extra bytes to allocate.
00266     if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM)
00267     {
00268         this->m_pwfx = (WAVEFORMATEX*) n_new(char[sizeof(WAVEFORMATEX)]);
00269         n_assert(this->m_pwfx);
00270 
00271         // Copy the bytes from the pcm structure to the waveformatex structure
00272         memcpy(this->m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat));
00273         this->m_pwfx->cbSize = 0;
00274     }
00275     else
00276     {
00277         // read in length of extra bytes
00278         WORD cbExtraBytes = 0L;
00279         if (mmioRead(m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD))
00280         {
00281             return false;
00282         }
00283 
00284         this->m_pwfx = (WAVEFORMATEX*)n_new(char[sizeof(WAVEFORMATEX) + cbExtraBytes]);
00285         n_assert(this->m_pwfx);
00286 
00287         // Copy the bytes from the pcm structure to the waveformatex structure
00288         memcpy(this->m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat));
00289         this->m_pwfx->cbSize = cbExtraBytes;
00290 
00291         // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
00292         if (mmioRead(this->m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize)) + sizeof(WORD)), cbExtraBytes) != cbExtraBytes)
00293         {
00294             n_delete(this->m_pwfx);
00295             this->m_pwfx = 0;
00296             return false;
00297         }
00298     }
00299 
00300     // ascend the input file out of the 'fmt ' chunk
00301     if (0 != mmioAscend(this->m_hmmio, &ckIn, 0))
00302     {
00303         n_delete(this->m_pwfx);
00304         this->m_pwfx = 0;
00305         return false;
00306     }
00307     return true;
00308 }
00309 
00310 //------------------------------------------------------------------------------
00314 bool
00315 nWavFile::Reset()
00316 {
00317     n_assert(this->m_hmmio);
00318 
00319     // seek to the data
00320     if (-1 == mmioSeek(this->m_hmmio, this->m_ckRiff.dwDataOffset + sizeof(FOURCC), SEEK_SET))
00321     {
00322         return false;
00323     }
00324 
00325     // search for 'data' chunk
00326     this->m_ck.ckid = mmioFOURCC('d','a','t','a');
00327     if (0 != mmioDescend(this->m_hmmio, &this->m_ck, &this->m_ckRiff, MMIO_FINDCHUNK))
00328     {
00329         return false;
00330     }
00331     return true;
00332 }
00333 
00334 //------------------------------------------------------------------------------
00342 uint
00343 nWavFile::Read(void* buffer, uint bytesToRead)
00344 {
00345     n_assert(this->IsOpen());
00346     n_assert(this->m_hmmio);
00347     n_assert(buffer);
00348     n_assert(bytesToRead > 0);
00349 
00350     MMIOINFO mmioInfoIn;    // current status of m_hmmio
00351     mmioGetInfo(this->m_hmmio, &mmioInfoIn, 0);
00352 
00353     uint cbDataIn = bytesToRead;
00354     if (cbDataIn > this->m_ck.cksize)
00355     {
00356         cbDataIn = this->m_ck.cksize;
00357     }
00358     this->m_ck.cksize -= cbDataIn;
00359 
00360     DWORD cT;
00361     for (cT = 0; cT < cbDataIn; cT++)
00362     {
00363         // read next chunk if necessary
00364         if (mmioInfoIn.pchNext == mmioInfoIn.pchEndRead)
00365         {
00366             mmioAdvance(this->m_hmmio, &mmioInfoIn, MMIO_READ);
00367         }
00368 
00369         // copy to buffer
00370         *((uchar*)buffer + cT) = *((uchar*)mmioInfoIn.pchNext);
00371         mmioInfoIn.pchNext++;
00372     }
00373     mmioSetInfo(this->m_hmmio, &mmioInfoIn, 0);
00374     return cbDataIn;
00375 }

Copyright © 1999-2005 by the contributing authors. Ideas, requests, problems: Send feedback.