From: <sag...@us...> - 2013-07-03 23:11:10
|
Revision: 2488 http://sourceforge.net/p/modplug/code/2488 Author: saga-games Date: 2013-07-03 23:10:59 +0000 (Wed, 03 Jul 2013) Log Message: ----------- [Ref] Use unified WAVWriter class for mod export, sample saving and sample copying. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mod2wave.cpp trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/SampleIO.cpp trunk/OpenMPT/soundlib/WAVTools.cpp trunk/OpenMPT/soundlib/WAVTools.h trunk/OpenMPT/soundlib/Wav.h Modified: trunk/OpenMPT/mptrack/Mod2wave.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-07-03 22:45:08 UTC (rev 2487) +++ trunk/OpenMPT/mptrack/Mod2wave.cpp 2013-07-03 23:10:59 UTC (rev 2488) @@ -17,6 +17,8 @@ #include "vstplug.h" #include "mod2wave.h" #include "Wav.h" +#include "WAVTools.h" +#include "../common/version.h" #include "ACMConvert.h" extern UINT nMixingRates[NUMMIXRATE]; @@ -596,16 +598,12 @@ void CDoWaveConvert::OnButton1() //------------------------------ { - FILE *f; - WAVEFILEHEADER header; - WAVEDATAHEADER datahdr, fmthdr; MSG msg; BYTE buffer[WAVECONVERTBUFSIZE]; CHAR s[80]; HWND progress = ::GetDlgItem(m_hWnd, IDC_PROGRESS1); UINT ok = IDOK, pos = 0; uint64 ullSamples = 0, ullMaxSamples; - DWORD dwDataOffset; LONG lMax = 256; if (!m_pSndFile || !m_lpszFileName) @@ -614,13 +612,15 @@ return; } - while((f = fopen(m_lpszFileName, "w+b")) == NULL) + WAVWriter file(m_lpszFileName); + while(!file.IsValid()) { if(Reporting::RetryCancel("Could not open file for writing. Is it open in another application?") == rtyCancel) { EndDialog(IDCANCEL); return; } + file.Open(m_lpszFileName); } MixerSettings oldmixersettings = m_pSndFile->m_MixerSettings; @@ -647,26 +647,11 @@ m_pSndFile->InitPlayer(TRUE); if ((!m_dwFileLimit) || (m_dwFileLimit > 2047*1024)) m_dwFileLimit = 2047*1024; // 2GB m_dwFileLimit <<= 10; - // File Header - header.id_RIFF = IFFID_RIFF; - header.filesize = sizeof(WAVEFILEHEADER) - 8; - header.id_WAVE = IFFID_WAVE; - // Wave Format Header - fmthdr.id_data = IFFID_fmt; - fmthdr.length = 16; - if (m_pWaveFormat->cbSize) fmthdr.length += 2 + m_pWaveFormat->cbSize; - header.filesize += sizeof(fmthdr) + fmthdr.length; - // Data header - datahdr.id_data = IFFID_data; - datahdr.length = 0; - header.filesize += sizeof(datahdr); - // Writing Headers - fwrite(&header, 1, sizeof(header), f); - fwrite(&fmthdr, 1, sizeof(fmthdr), f); - fwrite(m_pWaveFormat, 1, fmthdr.length, f); - fwrite(&datahdr, 1, sizeof(datahdr), f); - dwDataOffset = ftell(f); - ullSamples = 0; + + file.WriteFormat(m_pWaveFormat->nSamplesPerSec, m_pWaveFormat->wBitsPerSample, m_pWaveFormat->nChannels, m_pWaveFormat->wBitsPerSample == 32 ? WAVFormatChunk::fmtFloat : WAVFormatChunk::fmtPCM); + + file.StartChunk(RIFFChunk::iddata); + ullMaxSamples = m_dwFileLimit / (m_pWaveFormat->nChannels * m_pWaveFormat->wBitsPerSample / 8); if (m_dwSongLimit) { @@ -701,6 +686,10 @@ // For giving away some processing time every now and then DWORD dwSleepTime = dwStartTime; + size_t bytesWritten = 0; + + CMainFrame::GetMainFrame()->PauseMod(); + m_pSndFile->m_SongFlags.reset(SONG_STEP | SONG_PATTERNLOOP); CMainFrame::GetMainFrame()->InitRenderer(m_pSndFile); //rewbs.VSTTimeInfo for (UINT n = 0; ; n++) { @@ -739,18 +728,19 @@ } } - UINT lWrite = fwrite(buffer, 1, lRead*nBytesPerSample, f); + UINT lWrite = fwrite(buffer, 1, lRead * nBytesPerSample, file.GetFile()); if (!lWrite) break; - datahdr.length += lWrite; + bytesWritten += lWrite; + if (m_bNormalize) { - ULONGLONG d = ((ULONGLONG)datahdr.length * m_pWaveFormat->wBitsPerSample) / 24; + ULONGLONG d = ((ULONGLONG)bytesWritten * m_pWaveFormat->wBitsPerSample) / 24; if (d >= m_dwFileLimit) break; } else { - if (datahdr.length >= m_dwFileLimit) + if (bytesWritten >= m_dwFileLimit) break; } if (ullSamples >= ullMaxSamples) @@ -766,7 +756,7 @@ timeRemaining = static_cast<DWORD>(((dwCurrentTime - dwStartTime) * (max - ullSamples) / ullSamples) / 1000); } - wsprintf(s, "Writing file... (%uKB, %umn%02us, %umn%02us remaining)", datahdr.length >> 10, l / 60, l % 60, timeRemaining / 60, timeRemaining % 60); + wsprintf(s, "Writing file... (%uKB, %umn%02us, %umn%02us remaining)", bytesWritten >> 10, l / 60, l % 60, timeRemaining / 60, timeRemaining % 60); SetDlgItemText(IDC_TEXT1, s); // Give windows some time to redraw the window, if necessary (else, the infamous "OpenMPT does not respond" will pop up) @@ -798,25 +788,25 @@ if (m_bNormalize) { - DWORD dwLength = datahdr.length; + DWORD dwLength = bytesWritten; DWORD percent = 0xFF, dwPos, dwSize, dwCount; DWORD dwBitSize, dwOutPos; - dwPos = dwOutPos = dwDataOffset; + dwPos = dwOutPos = file.GetPosition(); dwBitSize = m_pWaveFormat->wBitsPerSample / 8; - datahdr.length = 0; + bytesWritten = 0; ::SendMessage(progress, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); dwCount = dwLength; while (dwCount >= 3) { dwSize = (sizeof(buffer) / 3) * 3; if (dwSize > dwCount) dwSize = dwCount; - fseek(f, dwPos, SEEK_SET); - if (fread(buffer, 1, dwSize, f) != dwSize) break; + fseek(file.GetFile(), dwPos, SEEK_SET); + if (fread(buffer, 1, dwSize, file.GetFile()) != dwSize) break; m_pSndFile->Normalize24BitBuffer(buffer, dwSize, lMax, dwBitSize); - fseek(f, dwOutPos, SEEK_SET); - datahdr.length += (dwSize/3)*dwBitSize; - fwrite(buffer, 1, (dwSize/3)*dwBitSize, f); + fseek(file.GetFile(), dwOutPos, SEEK_SET); + bytesWritten += (dwSize / 3) * dwBitSize; + fwrite(buffer, 1, (dwSize / 3) * dwBitSize, file.GetFile()); dwCount -= dwSize; dwPos += dwSize; dwOutPos += (dwSize * m_pWaveFormat->wBitsPerSample) / 24; @@ -831,43 +821,43 @@ } } + file.Skip(bytesWritten); + file.Truncate(); + // Write cue points - DWORD cuePointLength = 0; if(m_pSndFile->m_PatternCuePoints.size() > 0) { // Cue point header - WavCueHeader cuehdr; - cuehdr.id = IFFID_cue; - cuehdr.numPoints = m_pSndFile->m_PatternCuePoints.size(); - cuehdr.length = 4 + cuehdr.numPoints * sizeof(WavCuePoint); - cuePointLength = 8 + cuehdr.length; - cuehdr.ConvertEndianness(); - fwrite(&cuehdr, 1, sizeof(WavCueHeader), f); + file.StartChunk(RIFFChunk::idcue_); + uint32 numPoints = m_pSndFile->m_PatternCuePoints.size(); + SwapBytesLE(numPoints); + file.Write(numPoints); // Write all cue points std::vector<PatternCuePoint>::const_iterator iter; - DWORD num = 0; - for(iter = m_pSndFile->m_PatternCuePoints.begin(); iter != m_pSndFile->m_PatternCuePoints.end(); ++iter, num++) + uint32 index = 0; + for(iter = m_pSndFile->m_PatternCuePoints.begin(); iter != m_pSndFile->m_PatternCuePoints.end(); iter++) { - WavCuePoint cuepoint; - cuepoint.id = num; - cuepoint.pos = (uint32)iter->offset; - cuepoint.chunkID = IFFID_data; - cuepoint.chunkStart = 0; // we use no Wave List Chunk (wavl) as we have only one data block, so this should be 0. - cuepoint.blockStart = 0; // dito - cuepoint.offset = (uint32)iter->offset; - cuepoint.ConvertEndianness(); - fwrite(&cuepoint, 1, sizeof(WavCuePoint), f); + WAVCuePoint cuePoint; + cuePoint.id = index++; + cuePoint.position = static_cast<uint32>(iter->offset); + cuePoint.riffChunkID = static_cast<uint32>(RIFFChunk::iddata); + cuePoint.chunkStart = 0; // we use no Wave List Chunk (wavl) as we have only one data block, so this should be 0. + cuePoint.blockStart = 0; // dito + cuePoint.offset = cuePoint.position; + cuePoint.ConvertEndianness(); + file.Write(cuePoint); } m_pSndFile->m_PatternCuePoints.clear(); } - header.filesize = (sizeof(WAVEFILEHEADER) - 8) + (8 + fmthdr.length) + (8 + datahdr.length) + (cuePointLength); - fseek(f, 0, SEEK_SET); - fwrite(&header, sizeof(header), 1, f); - fseek(f, dwDataOffset-sizeof(datahdr), SEEK_SET); - fwrite(&datahdr, sizeof(datahdr), 1, f); - fclose(f); + WAVWriter::Metatags tags; + tags.push_back(WAVWriter::Metatag(RIFFChunk::idINAM, m_pSndFile->GetTitle())); + tags.push_back(WAVWriter::Metatag(RIFFChunk::idISFT, MptVersion::GetOpenMPTVersionStr())); + file.WriteMetatags(tags); + + size_t fileSize = file.Finalize(); + m_pSndFile->m_nMaxOrderPosition = 0; if (m_bNormalize) { @@ -875,7 +865,7 @@ CFile fw; if (fw.Open(m_lpszFileName, CFile::modeReadWrite | CFile::modeNoTruncate)) { - fw.SetLength(header.filesize+8); + fw.SetLength(fileSize); fw.Close(); } } Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2013-07-03 22:45:08 UTC (rev 2487) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2013-07-03 23:10:59 UTC (rev 2488) @@ -21,14 +21,12 @@ #include "view_smp.h" #include "../soundlib/MIDIEvents.h" #include "SampleEditorDialogs.h" -#include "modsmp_ctrl.h" -#include "Wav.h" +#include "../soundlib/WAVTools.h" #include "../soundlib/FileReader.h" #define new DEBUG_NEW - // Non-client toolbar #define SMP_LEFTBAR_CY 29 #define SMP_LEFTBAR_CXSEP 14 @@ -1862,117 +1860,86 @@ //---------------------------- { CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); - CModDoc *pModDoc = GetDocument(); - CSoundFile *pSndFile; - DWORD dwMemSize, dwSmpLen, dwSmpOffset; - HGLOBAL hCpy; - BOOL bExtra = TRUE; + if(pMainFrm == nullptr || GetDocument() == nullptr) + { + return; + } - if ((!pMainFrm) || (!pModDoc)) return; - pSndFile = pModDoc->GetSoundFile(); - const ModSample &sample = pSndFile->GetSample(m_nSample); - if ((!sample.nLength) || (!sample.pSample)) return; - dwMemSize = sample.nLength; - dwSmpOffset = 0; - if (m_dwEndSel > sample.nLength) m_dwEndSel = sample.nLength; - if (m_dwEndSel > m_dwBeginSel) { dwMemSize = m_dwEndSel - m_dwBeginSel; dwSmpOffset = m_dwBeginSel; bExtra = FALSE; } - if (sample.uFlags & CHN_16BIT) { dwMemSize <<= 1; dwSmpOffset <<= 1; } - if (sample.uFlags & CHN_STEREO) { dwMemSize <<= 1; dwSmpOffset <<= 1; } - dwSmpLen = dwMemSize; - dwMemSize += sizeof(WAVEFILEHEADER) + sizeof(WAVEFORMATHEADER) + sizeof(WAVEDATAHEADER) - + sizeof(WAVEEXTRAHEADER) + sizeof(WAVESAMPLERINFO); - // For name + fname - dwMemSize += 32 * 2; - BeginWaitCursor(); - if ((pMainFrm->OpenClipboard()) && ((hCpy = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, dwMemSize))!=NULL)) + const CSoundFile &sndFile = GetDocument()->GetrSoundFile(); + const ModSample &sample = sndFile.GetSample(m_nSample); + + bool addLoopInfo = true; + size_t smpSize = sample.nLength; + size_t smpOffset = 0; + + // First things first: Calculate sample size, taking partial selections into account. + LimitMax(m_dwEndSel, sample.nLength); + if(m_dwEndSel > m_dwBeginSel) { - EmptyClipboard(); - LPBYTE p = (LPBYTE)GlobalLock(hCpy); - WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)p; - WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(p + sizeof(WAVEFILEHEADER)); - WAVEDATAHEADER *pdata = (WAVEDATAHEADER *)(p + sizeof(WAVEFILEHEADER) + sizeof(WAVEFORMATHEADER)); - phdr->id_RIFF = IFFID_RIFF; - phdr->filesize = sizeof(WAVEFILEHEADER) + sizeof(WAVEFORMATHEADER) + sizeof(WAVEDATAHEADER) - 8; - phdr->id_WAVE = IFFID_WAVE; - pfmt->id_fmt = IFFID_fmt; - pfmt->hdrlen = 16; - pfmt->format = 1; - pfmt->freqHz = sample.nC5Speed; - if (pSndFile->m_nType & (MOD_TYPE_MOD|MOD_TYPE_XM)) - { - pfmt->freqHz = ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); + smpSize = m_dwEndSel - m_dwBeginSel; + smpOffset = m_dwBeginSel; + addLoopInfo = false; } - pfmt->channels = (sample.uFlags & CHN_STEREO) ? (WORD)2 : (WORD)1; - pfmt->bitspersample = (sample.uFlags & CHN_16BIT) ? (WORD)16 : (WORD)8; - pfmt->samplesize = pfmt->channels * pfmt->bitspersample / 8; - pfmt->bytessec = pfmt->freqHz*pfmt->samplesize; - pdata->id_data = IFFID_data; - pdata->length = dwSmpLen; - phdr->filesize += pdata->length; - LPBYTE psamples = p + sizeof(WAVEFILEHEADER) + sizeof(WAVEFORMATHEADER) + sizeof(WAVEDATAHEADER); - memcpy(psamples, static_cast<const char *>(sample.pSample) + dwSmpOffset, dwSmpLen); - if (pfmt->bitspersample == 8) + + smpSize *= sample.GetBytesPerSample(); + smpOffset *= sample.GetBytesPerSample(); + + // Ok, now calculate size of the resulting WAV file. + size_t memSize = sizeof(RIFFHeader) // RIFF Header + + sizeof(RIFFChunk) + sizeof(WAVFormatChunk) // Sample format + + sizeof(RIFFChunk) + ((smpSize + 1) & ~1) // Sample data + + sizeof(RIFFChunk) + sizeof(WAVExtraChunk) // Sample metadata + + MAX_SAMPLENAME + MAX_SAMPLEFILENAME; // Sample name + STATIC_ASSERT((sizeof(WAVExtraChunk) % 2u) == 0); + STATIC_ASSERT((MAX_SAMPLENAME % 2u) == 0); + STATIC_ASSERT((MAX_SAMPLEFILENAME % 2u) == 0); + + if(addLoopInfo) { - for (UINT i = 0; i < dwSmpLen; i++) psamples[i] += 0x80; + // We want to store some loop metadata as well. + memSize += sizeof(RIFFChunk) + sizeof(WAVSampleInfoChunk) + 2 * sizeof(WAVSampleLoop); } - if (bExtra) - { - WAVESMPLHEADER *psh = (WAVESMPLHEADER *)(psamples+dwSmpLen); - MemsetZero(*psh); - psh->smpl_id = 0x6C706D73; - psh->smpl_len = sizeof(WAVESMPLHEADER) - 8; - psh->dwSamplePeriod = 22675; - if (sample.nC5Speed > 256) psh->dwSamplePeriod = 1000000000 / sample.nC5Speed; - psh->dwBaseNote = 60; - // Write loops - WAVESAMPLERINFO *psmpl = (WAVESAMPLERINFO *)psh; - MemsetZero(psmpl->wsiLoops); - if((sample.uFlags & CHN_SUSTAINLOOP) != 0) + ASSERT((memSize % 2u) == 0); + + BeginWaitCursor(); + HGLOBAL hCpy; + if(pMainFrm->OpenClipboard() && (hCpy = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, memSize)) != nullptr) { - psmpl->wsiLoops[psmpl->wsiHdr.dwSampleLoops++].SetLoop(sample.nSustainStart, sample.nSustainEnd, (sample.uFlags & CHN_PINGPONGSUSTAIN) != 0); - psmpl->wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); - } - if((sample.uFlags & CHN_LOOP) != 0) - { - psmpl->wsiLoops[psmpl->wsiHdr.dwSampleLoops++].SetLoop(sample.nLoopStart, sample.nLoopEnd, (sample.uFlags & CHN_PINGPONGLOOP) != 0); - psmpl->wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); - } + EmptyClipboard(); - WAVEEXTRAHEADER *pxh = (WAVEEXTRAHEADER *)(psamples+dwSmpLen+psh->smpl_len+8); - pxh->xtra_id = IFFID_xtra; - pxh->xtra_len = sizeof(WAVEEXTRAHEADER)-8; + void *p = GlobalLock(hCpy); + WAVWriter file(p, memSize); - pxh->dwFlags = sample.uFlags; - pxh->wPan = sample.nPan; - pxh->wVolume = sample.nVolume; - pxh->wGlobalVol = sample.nGlobalVol; + // Write sample format + file.WriteFormat(sample.GetSampleRate(sndFile.GetType()), sample.GetElementarySampleSize() * 8, sample.GetNumChannels(), WAVFormatChunk::fmtPCM); - pxh->nVibType = sample.nVibType; - pxh->nVibSweep = sample.nVibSweep; - pxh->nVibDepth = sample.nVibDepth; - pxh->nVibRate = sample.nVibRate; - if((pSndFile->GetType() & MOD_TYPE_XM) && (pxh->nVibDepth | pxh->nVibRate)) - { - // XM vibrato is upside down - pxh->nVibSweep = 255 - pxh->nVibSweep; - } + // Write sample data + file.StartChunk(RIFFChunk::iddata); - if ((pSndFile->m_szNames[m_nSample][0]) || (sample.filename[0])) + uint8 *sampleData = static_cast<uint8 *>(p) + file.GetPosition(); + memcpy(sampleData, static_cast<const char *>(sample.pSample) + smpOffset, smpSize); + if(sample.GetElementarySampleSize() == 1) { - LPSTR pszText = (LPSTR)(pxh+1); - memcpy(pszText, pSndFile->m_szNames[m_nSample], MAX_SAMPLENAME); - pxh->xtra_len += MAX_SAMPLENAME; - if (sample.filename[0]) + // 8-Bit samples have to be unsigned. + for(size_t i = smpSize; i != 0; i--) { - memcpy(pszText + MAX_SAMPLENAME, sample.filename, MAX_SAMPLEFILENAME); - pxh->xtra_len += MAX_SAMPLEFILENAME; + *(sampleData++) += 0x80u; } } - phdr->filesize += (psh->smpl_len + 8) + (pxh->xtra_len + 8); + + file.Skip(smpSize); + + if(addLoopInfo) + { + file.WriteLoopInformation(sample); } + file.WriteExtraInformation(sample, sndFile.GetType(), sndFile.GetSampleName(m_nSample)); + + file.Finalize(); + GlobalUnlock(hCpy); - SetClipboardData (CF_WAVE, (HANDLE) hCpy); + SetClipboardData (CF_WAVE, (HANDLE)hCpy); CloseClipboard(); } EndWaitCursor(); Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-07-03 22:45:08 UTC (rev 2487) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-07-03 23:10:59 UTC (rev 2488) @@ -430,144 +430,33 @@ bool CSoundFile::SaveWAVSample(SAMPLEINDEX nSample, const LPCSTR lpszFileName) const //---------------------------------------------------------------------------------- { - std::string softwareIdString = MptVersion::GetOpenMPTVersionStr(); - const char *softwareId = softwareIdString.c_str(); - size_t softwareIdLength = strlen(softwareId) + 1; + WAVWriter file(lpszFileName); - WAVEFILEHEADER header; - WAVEFORMATHEADER format; - WAVEDATAHEADER data; - WAVESAMPLERINFO smpl; - WAVELISTHEADER list; - WAVEEXTRAHEADER extra; - const ModSample &sample = Samples[nSample]; - FILE *f; - - if ((f = fopen(lpszFileName, "wb")) == NULL) return false; - MemsetZero(extra); - MemsetZero(smpl); - header.id_RIFF = LittleEndian(IFFID_RIFF); - header.filesize = sizeof(header) - 8 + sizeof(format) + sizeof(data) + sizeof(extra) - + sizeof(list) + 8 + softwareIdLength + 8 + 32; // LIST(INAM, ISFT) - header.id_WAVE = LittleEndian(IFFID_WAVE); - format.id_fmt = LittleEndian(IFFID_fmt); - format.hdrlen = LittleEndian(16); - format.format = LittleEndianW(1); - if(!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM))) - format.freqHz = LittleEndian(sample.nC5Speed); - else - format.freqHz = LittleEndian(ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune)); - format.channels = LittleEndianW(sample.GetNumChannels()); - format.bitspersample = LittleEndianW(sample.GetElementarySampleSize() * 8); - format.samplesize = LittleEndianW(sample.GetBytesPerSample()); - format.bytessec = LittleEndian(format.freqHz * format.samplesize); - - data.id_data = LittleEndian(IFFID_data); - data.length = sample.GetSampleSizeInBytes(); - - header.filesize += data.length; - if((data.length % 2u) != 0) + if(!file.IsValid()) { - // Write padding byte if sample size is odd. - header.filesize++; + return false; } - if((softwareIdLength % 2u) != 0) - { - header.filesize++; - } - // "smpl" field - smpl.wsiHdr.smpl_id = LittleEndian(IFFID_smpl); - smpl.wsiHdr.smpl_len = sizeof(WAVESMPLHEADER) - 8; - if (sample.nC5Speed >= 256) - smpl.wsiHdr.dwSamplePeriod = LittleEndian(1000000000 / sample.nC5Speed); - else - smpl.wsiHdr.dwSamplePeriod = LittleEndian(22675); // 44100 Hz + const ModSample &sample = Samples[nSample]; + file.WriteFormat(sample.GetSampleRate(GetType()), sample.GetElementarySampleSize() * 8, sample.GetNumChannels(), WAVFormatChunk::fmtPCM); - smpl.wsiHdr.dwBaseNote = LittleEndian(NOTE_MIDDLEC - NOTE_MIN); - - // Write loops - if((sample.uFlags & CHN_SUSTAINLOOP) != 0) - { - smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(sample.nSustainStart, sample.nSustainEnd, (sample.uFlags & CHN_PINGPONGSUSTAIN) != 0); - smpl.wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); - } - if((sample.uFlags & CHN_LOOP) != 0) - { - smpl.wsiLoops[smpl.wsiHdr.dwSampleLoops++].SetLoop(sample.nLoopStart, sample.nLoopEnd, (sample.uFlags & CHN_PINGPONGLOOP) != 0); - smpl.wsiHdr.smpl_len += sizeof(SAMPLELOOPSTRUCT); - } - - // Update file length in header - header.filesize += smpl.wsiHdr.smpl_len + 8; - - header.filesize = LittleEndian(header.filesize); - data.length = LittleEndian(data.length); - smpl.wsiHdr.smpl_len = LittleEndian(smpl.wsiHdr.smpl_len); - fwrite(&header, 1, sizeof(header), f); - fwrite(&format, 1, sizeof(format), f); - fwrite(&data, 1, sizeof(data), f); - - SampleIO( - (sample.uFlags & CHN_16BIT) ? SampleIO::_16bit : SampleIO::_8bit, - (sample.uFlags & CHN_STEREO) ? SampleIO::stereoInterleaved : SampleIO::mono, + // Write sample data + file.StartChunk(RIFFChunk::iddata); + file.Skip(SampleIO( + sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, + sample.uFlags[CHN_STEREO] ? SampleIO::stereoInterleaved : SampleIO::mono, SampleIO::littleEndian, - (sample.uFlags & CHN_16BIT) ? SampleIO::signedPCM : SampleIO::unsignedPCM) - .WriteSample(f, sample); + sample.uFlags[CHN_16BIT] ? SampleIO::signedPCM : SampleIO::unsignedPCM) + .WriteSample(file.GetFile(), sample)); - if((data.length % 2u) != 0) - { - // Write padding byte if sample size is odd. - int8 padding = 0; - fwrite(&padding, 1, 1, f); - } - fwrite(&smpl, 1, smpl.wsiHdr.smpl_len + 8, f); + file.WriteLoopInformation(sample); + file.WriteExtraInformation(sample, GetType()); - // "LIST" field - list.list_id = LittleEndian(IFFID_LIST); - list.list_len = LittleEndian(sizeof(list) - 8 // LIST - + 8 + 32 // "INAM".dwLen.szSampleName - + 8 + softwareIdLength); // "ISFT".dwLen.softwareId.0 - list.info = LittleEndian(IFFID_INFO); - fwrite(&list, 1, sizeof(list), f); - - list.list_id = LittleEndian(IFFID_INAM); // "INAM" - list.list_len = LittleEndian(32); - fwrite(&list, 1, 8, f); - fwrite(m_szNames[nSample], 1, 32, f); - - list.list_id = LittleEndian(IFFID_ISFT); // "ISFT" - list.list_len = LittleEndian(softwareIdLength); - fwrite(&list, 1, 8, f); - fwrite(softwareId, 1, list.list_len, f); - if((softwareIdLength % 2u) != 0) - { - int8 padding = 0; - fwrite(&padding, 1, 1, f); - } - - // "xtra" field - extra.xtra_id = LittleEndian(IFFID_xtra); - extra.xtra_len = LittleEndian(sizeof(extra) - 8); - - extra.dwFlags = LittleEndian(sample.uFlags); - extra.wPan = LittleEndianW(sample.nPan); - extra.wVolume = LittleEndianW(sample.nVolume); - extra.wGlobalVol = LittleEndianW(sample.nGlobalVol); - extra.wReserved = 0; - - extra.nVibType = sample.nVibType; - extra.nVibSweep = sample.nVibSweep; - extra.nVibDepth = sample.nVibDepth; - extra.nVibRate = sample.nVibRate; - if((GetType() & MOD_TYPE_XM) && (extra.nVibDepth | extra.nVibRate)) - { - // XM vibrato is upside down - extra.nVibSweep = 255 - extra.nVibSweep; - } - - fwrite(&extra, 1, sizeof(extra), f); - fclose(f); + WAVWriter::Metatags tags; + tags.push_back(WAVWriter::Metatag(RIFFChunk::idINAM, m_szNames[nSample])); + tags.push_back(WAVWriter::Metatag(RIFFChunk::idISFT, MptVersion::GetOpenMPTVersionStr())); + file.WriteMetatags(tags); + return true; } @@ -609,8 +498,7 @@ typedef struct PACKED GF1PATCHFILEHEADER { - DWORD gf1p; // "GF1P" - DWORD atch; // "ATCH" + char magic[8]; // "GF1PATCH" CHAR version[4]; // "100", or "110" CHAR id[10]; // "ID#000002" CHAR copyright[60]; // Copyright @@ -776,7 +664,7 @@ GF1INSTRUMENT *pinshdr = (GF1INSTRUMENT *)(lpStream+sizeof(GF1PATCHFILEHEADER)); if ((!lpStream) || (dwMemLength < 512) - || (phdr->gf1p != 0x50314647) || (phdr->atch != 0x48435441) + || memcmp(phdr->magic, "GF1PATCH", 8) || (phdr->version[3] != 0) || (phdr->id[9] != 0) || (phdr->instrum < 1) || (!phdr->samples) || (!pinshdr->layers)) return false; @@ -803,7 +691,7 @@ UINT nSamples; if ((!lpStream) || (dwMemLength < 512) - || (phdr->gf1p != 0x50314647) || (phdr->atch != 0x48435441) + || memcmp(phdr->magic, "GF1PATCH", 8) || (phdr->version[3] != 0) || (phdr->id[9] != 0) || (phdr->instrum < 1) || (!phdr->samples) || (!pih->layers) || (!plh->samples)) return false; @@ -1928,8 +1816,7 @@ { FileReader::off_t readBytes = *bytes; LimitMax(readBytes, file.BytesLeft()); - memcpy(buffer, file.GetRawData(), readBytes); - file.Skip(readBytes); + file.ReadRaw(reinterpret_cast<char *>(buffer), readBytes); *bytes = readBytes; if(*bytes == 0) return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; @@ -2080,7 +1967,7 @@ { #ifndef NO_FLAC // Check if we're dealing with FLAC in an OGG container. - // We won't check for the "fLaC" signature but let libFLAC decide whether a file is valid or not, as some FLAC files might have e.g. leading ID3v2 data. + // <del>We won't check for the "fLaC" signature but let libFLAC decide whether a file is valid or not, as some FLAC files might have e.g. leading ID3v2 data.</del> Apparently we do that now. file.Rewind(); if(!file.ReadMagic("fLaC")) { @@ -2312,8 +2199,7 @@ { FileReader &file = *static_cast<FileReader *>(fp); size_t readBytes = std::min(count, static_cast<size_t>(file.BytesLeft())); - memcpy(buf, file.GetRawData(), readBytes); - file.Skip(readBytes); + file.ReadRaw(static_cast<char *>(buf), readBytes); return readBytes; } Modified: trunk/OpenMPT/soundlib/SampleIO.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleIO.cpp 2013-07-03 22:45:08 UTC (rev 2487) +++ trunk/OpenMPT/soundlib/SampleIO.cpp 2013-07-03 23:10:59 UTC (rev 2488) @@ -539,7 +539,8 @@ else if((GetBitDepth() == 8 || (GetBitDepth() == 16 && GetEndianness() == littleEndian)) && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { // Stereo signed interleaved - if(f) fwrite(pSample, 1, sample.GetSampleSizeInBytes(), f); + len = sample.GetSampleSizeInBytes(); + if(f) fwrite(pSample, 1, len, f); } else if(GetBitDepth() == 8 && GetChannelFormat() == stereoInterleaved && GetEncoding() == unsignedPCM) Modified: trunk/OpenMPT/soundlib/WAVTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.cpp 2013-07-03 22:45:08 UTC (rev 2487) +++ trunk/OpenMPT/soundlib/WAVTools.cpp 2013-07-03 23:10:59 UTC (rev 2488) @@ -222,3 +222,310 @@ fraction = 0; playCount = 0; } + + +/////////////////////////////////////////////////////////// +// WAV Writing + + +// Output to file: Initialize with filename. +WAVWriter::WAVWriter(const char *filename) : f(nullptr), memory(nullptr), memSize(0) +//---------------------------------------------------------------------------------- +{ + Open(filename); +} + + +// Output to clipboard: Initialize with pointer to memory and size of reserved memory. +WAVWriter::WAVWriter(void *mem, size_t size) : f(nullptr), memory(static_cast<uint8 *>(mem)), memSize(size) +//--------------------------------------------------------------------------------------------------------- +{ + Init(); +} + + +WAVWriter::~WAVWriter() +//--------------------- +{ + Finalize(); +} + + +// Open a file for writing. +void WAVWriter::Open(const char *filename) +//---------------------------------------- +{ + f = fopen(filename, "w+b"); + Init(); +} + + +// Reset all file variables. +void WAVWriter::Init() +//-------------------- +{ + chunkStartPos = 0; + position = 0; + totalSize = 0; + + // Skip file header for now + Seek(sizeof(RIFFHeader)); +} + + +// Finalize the file by closing the last open chunk and updating the file header. Returns total size of file. +size_t WAVWriter::Finalize() +//-------------------------- +{ + FinalizeChunk(); + + RIFFHeader fileHeader; + fileHeader.magic = RIFFHeader::idRIFF; + fileHeader.length = static_cast<uint32>(totalSize - 8); + fileHeader.type = RIFFHeader::idWAVE; + fileHeader.ConvertEndianness(); + + Seek(0); + Write(fileHeader); + + if(f != nullptr) + { +#ifdef _DEBUG + fseek(f, 0, SEEK_END); + size_t realSize = static_cast<size_t>(ftell(f)); + ASSERT(totalSize == realSize); +#endif + fclose(f); + } + + f = nullptr; + memory = nullptr; + + return totalSize; +} + + +// Write a new chunk header to the file. +void WAVWriter::StartChunk(RIFFChunk::id_type id) +//----------------------------------------------- +{ + FinalizeChunk(); + + chunkStartPos = position; + chunkHeader.id = id; + Skip(sizeof(chunkHeader)); +} + + +// End current chunk by updating the chunk header and writing a padding byte if necessary. +void WAVWriter::FinalizeChunk() +//----------------------------- +{ + if(chunkStartPos != 0) + { + const size_t chunkSize = position - (chunkStartPos + sizeof(RIFFChunk)); + chunkHeader.length = chunkSize; + chunkHeader.ConvertEndianness(); + + size_t curPos = position; + Seek(chunkStartPos); + Write(chunkHeader); + + Seek(curPos); + if((chunkSize % 2u) != 0) + { + // Write padding + uint8 padding = 0; + Write(padding); + } + + chunkStartPos = 0; + } +} + + +// Seek to a position in file. +void WAVWriter::Seek(size_t pos) +//------------------------------ +{ + position = pos; + totalSize = std::max(totalSize, position); + + if(f != nullptr) + { + fseek(f, position, SEEK_SET); + } +} + + +// Write some data to the file. +void WAVWriter::Write(const void *data, size_t numBytes) +//------------------------------------------------------ +{ + if(f != nullptr) + { + fwrite(data, numBytes, 1, f); + } else if(memory != nullptr) + { + if(position <= memSize && numBytes <= memSize - position) + { + memcpy(memory + position, data, numBytes); + } else + { + // Should never happen - did we calculate a wrong memory size? + ASSERT(false); + } + } + position += numBytes; + totalSize = std::max(totalSize, position); +} + + +// Write the WAV format to the file. +void WAVWriter::WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding) +//------------------------------------------------------------------------------------------------------------------------- +{ + StartChunk(RIFFChunk::idfmt_); + WAVFormatChunk wavFormat; + + bool extensible = (numChannels > 2); + + wavFormat.format = static_cast<uint16>(extensible ? WAVFormatChunk::fmtExtensible : encoding); + wavFormat.numChannels = numChannels; + wavFormat.sampleRate = sampleRate; + wavFormat.blockAlign = (bitDepth * numChannels + 7) / 8; + wavFormat.byteRate = wavFormat.sampleRate * wavFormat.blockAlign; + wavFormat.bitsPerSample = bitDepth; + + wavFormat.ConvertEndianness(); + Write(wavFormat); + + if(extensible) + { + WAVFormatChunkExtension extFormat; + extFormat.size = sizeof(WAVFormatChunkExtension) - sizeof(uint16); + extFormat.validBitsPerSample = bitDepth; + switch(numChannels) + { + case 1: + extFormat.channelMask = 0x0004; // FRONT_CENTER + break; + case 2: + extFormat.channelMask = 0x0003; // FRONT_LEFT | FRONT_RIGHT + break; + case 3: + extFormat.channelMask = 0x0103; // FRONT_LEFT | FRONT_RIGHT | BACK_CENTER + break; + case 4: + extFormat.channelMask = 0x0033; // FRONT_LEFT | FRONT_RIGHT | BACK_LEFT | BACK_RIGHT + break; + default: + extFormat.channelMask = 0; + break; + } + extFormat.subFormat = static_cast<uint16>(encoding); + const uint8 guid[] = { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }; + MemCopy<uint8[14]>(extFormat.guid, guid); + + extFormat.ConvertEndianness(); + Write(extFormat); + } +} + + +// Write text tags to the file. +void WAVWriter::WriteMetatags(const Metatags &tags) +//------------------------------------------------- +{ + StartChunk(RIFFChunk::idLIST); + const char info[] = { 'I', 'N', 'F', 'O' }; + WriteArray(info); + + for(Metatags::const_iterator iter = tags.begin(); iter != tags.end(); iter++) + { + const size_t length = iter->text.length() + 1; + if(length == 1) + { + continue; + } + + RIFFChunk chunk; + chunk.id = static_cast<uint32>(iter->id); + chunk.length = length; + chunk.ConvertEndianness(); + Write(chunk); + Write(iter->text.c_str(), length); + + if((length % 2u) != 0) + { + uint8 padding = 0; + Write(padding); + } + } +} + + +// Write a sample loop information chunk to the file. +void WAVWriter::WriteLoopInformation(const ModSample &sample) +//----------------------------------------------------------- +{ + if(!sample.uFlags[CHN_LOOP | CHN_SUSTAINLOOP]) + { + return; + } + + StartChunk(RIFFChunk::idsmpl); + WAVSampleInfoChunk info; + + uint32 sampleRate = sample.nC5Speed; + if(sampleRate == 0) + { + sampleRate = ModSample::TransposeToFrequency(sample.RelativeTone, sample.nFineTune); + } + + info.ConvertToWAV(sampleRate); + + // Set up loops + WAVSampleLoop loops[2]; + if(sample.uFlags[CHN_SUSTAINLOOP]) + { + loops[info.numLoops++].ConvertToWAV(sample.nSustainStart, sample.nSustainEnd, sample.uFlags[CHN_PINGPONGSUSTAIN]); + } + if(sample.uFlags[CHN_LOOP]) + { + loops[info.numLoops++].ConvertToWAV(sample.nLoopStart, sample.nLoopEnd, sample.uFlags[CHN_PINGPONGLOOP]); + } + + info.ConvertEndianness(); + Write(info); + for(size_t i = 0; i < info.numLoops; i++) + { + loops[i].ConvertEndianness(); + Write(loops[i]); + } +} + + +// Write MPT's sample information chunk to the file. +void WAVWriter::WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName) +//----------------------------------------------------------------------------------------------------- +{ + StartChunk(RIFFChunk::idxtra); + WAVExtraChunk mptInfo; + + mptInfo.ConvertToWAV(sample, modType); + mptInfo.ConvertEndianness(); + Write(mptInfo); + + if(sampleName != nullptr) + { + // Write sample name (clipboard only) + char name[MAX_SAMPLENAME]; + mpt::String::Write<mpt::String::nullTerminated>(name, sampleName, MAX_SAMPLENAME); + WriteArray(name); + + char filename[MAX_SAMPLEFILENAME]; + mpt::String::Write<mpt::String::nullTerminated>(filename, sample.filename); + WriteArray(filename); + } +} Modified: trunk/OpenMPT/soundlib/WAVTools.h =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.h 2013-07-03 22:45:08 UTC (rev 2487) +++ trunk/OpenMPT/soundlib/WAVTools.h 2013-07-03 23:10:59 UTC (rev 2488) @@ -360,3 +360,101 @@ // Apply sample settings from file (loop points, MPT extra settings, ...) to a sample. void ApplySampleSettings(ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]); }; + + +//============= +class WAVWriter +//============= +{ +protected: + // When writing to file: File handle + FILE *f; + // When writing to memory: Memory address + length + uint8 *memory; + size_t memSize; + + // Cursor position + size_t position; + // Total number of bytes written to file / memory + size_t totalSize; + + // Currently written chunk + size_t chunkStartPos; + RIFFChunk chunkHeader; + +public: + + //============ + struct Metatag + //============ + { + Metatag(RIFFChunk::id_type tagID, std::string tagText) : id(tagID), text(tagText) { } + + RIFFChunk::id_type id; + std::string text; + }; + + typedef std::vector<Metatag> Metatags; + +public: + // Output to file: Initialize with filename. + WAVWriter(const char *filename); + // Output to clipboard: Initialize with pointer to memory and size of reserved memory. + WAVWriter(void *mem, size_t size); + + ~WAVWriter(); + + // Open a file for writing. + void Open(const char *filename); + + // Check if anything can be written to the file. + bool IsValid() const { return f != nullptr || memory != nullptr; } + + // Finalize the file by closing the last open chunk and updating the file header. Returns total size of file. + size_t Finalize(); + // Begin writing a new chunk to the file. + void StartChunk(RIFFChunk::id_type id); + + // Skip some bytes... For example after writing sample data. + void Skip(size_t numBytes) { Seek(position + numBytes); } + // Get file handle + FILE *GetFile() { return f; } + // Get position in file (not counting any changes done to the file from outside this class, i.e. through GetFile()) + size_t GetPosition() const { return position; } + + // Shrink file size to current position. + void Truncate() { totalSize = position; } + + // Write some data to the file. + template<typename T> + void Write(const T &data) + { + Write(&data, sizeof(T)); + } + + // Write an array to the file. + template<typename T, size_t size> + void WriteArray(const T (&data)[size]) + { + Write(data, sizeof(T) * size); + } + + // Write the WAV format to the file. + void WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding); + // Write text tags to the file. + void WriteMetatags(const Metatags &tags); + // Write a sample loop information chunk to the file. + void WriteLoopInformation(const ModSample &sample); + // Write MPT's sample information chunk to the file. + void WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName = nullptr); + +protected: + void Init(); + // Seek to a position in file. + void Seek(size_t pos); + // End current chunk by updating the chunk header and writing a padding byte if necessary. + void FinalizeChunk(); + + // Write some data to the file. + void Write(const void *data, size_t numBytes); +}; Modified: trunk/OpenMPT/soundlib/Wav.h =================================================================== --- trunk/OpenMPT/soundlib/Wav.h 2013-07-03 22:45:08 UTC (rev 2487) +++ trunk/OpenMPT/soundlib/Wav.h 2013-07-03 23:10:59 UTC (rev 2488) @@ -36,182 +36,29 @@ #define IFFID_wave 0x65766177 #define IFFID_fmt 0x20746D66 #define IFFID_wsmp 0x706D7377 -#define IFFID_pcm 0x206d6370 #define IFFID_data 0x61746164 -#define IFFID_smpl 0x6C706D73 -#define IFFID_xtra 0x61727478 -#define IFFID_cue 0x20657563 #ifdef NEEDS_PRAGMA_PACK #pragma pack(push, 1) #endif - -typedef struct PACKED WAVEFILEHEADER +struct PACKED WAVEFILEHEADER { DWORD id_RIFF; // "RIFF" DWORD filesize; // file length-8 DWORD id_WAVE; -} WAVEFILEHEADER; +}; STATIC_ASSERT(sizeof(WAVEFILEHEADER) == 12); - -typedef struct PACKED WAVEFORMATHEADER +struct PACKED WAVEDATAHEADER { - DWORD id_fmt; // "fmt " - DWORD hdrlen; // 16 - WORD format; // 1 - WORD channels; // 1:mono, 2:stereo - DWORD freqHz; // sampling freq - DWORD bytessec; // bytes/sec=freqHz*samplesize - WORD samplesize; // sizeof(sample) - WORD bitspersample; // bits per sample (8/16) -} WAVEFORMATHEADER; - -STATIC_ASSERT(sizeof(WAVEFORMATHEADER) == 24); - - -typedef struct PACKED WAVEDATAHEADER -{ DWORD id_data; // "data" DWORD length; // length of data -} WAVEDATAHEADER; +}; STATIC_ASSERT(sizeof(WAVEDATAHEADER) == 8); - - -typedef struct PACKED WAVESMPLHEADER -{ - // SMPL - DWORD smpl_id; // "smpl" -> 0x6C706D73 - DWORD smpl_len; // length of smpl: 3Ch (54h with sustain loop) - DWORD dwManufacturer; - DWORD dwProduct; - DWORD dwSamplePeriod; // 1000000000/freqHz - DWORD dwBaseNote; // 3Ch = C-4 -> 60 + RelativeTone - DWORD dwPitchFraction; - DWORD dwSMPTEFormat; - DWORD dwSMPTEOffset; - DWORD dwSampleLoops; // number of loops - DWORD cbSamplerData; -} WAVESMPLHEADER; - -STATIC_ASSERT(sizeof(WAVESMPLHEADER) == 44); - - -typedef struct PACKED SAMPLELOOPSTRUCT -{ - DWORD dwIdentifier; - DWORD dwLoopType; // 0=normal, 1=bidi - DWORD dwLoopStart; - DWORD dwLoopEnd; // Byte offset ? - DWORD dwFraction; - DWORD dwPlayCount; // Loop Count, 0=infinite - - // Set up a loop struct. - void SetLoop(DWORD loopStart, DWORD loopEnd, bool bidi) - { - dwIdentifier = 0; - dwLoopType = LittleEndian(bidi ? 1 : 0); - dwLoopStart = LittleEndian(loopStart); - // Loop ends are *inclusive* in the RIFF standard, while they're *exclusive* in OpenMPT. - if(loopEnd > loopStart) - { - dwLoopEnd = LittleEndian(loopEnd - 1); - } else - { - dwLoopEnd = LittleEndian(loopStart); - } - dwFraction = 0; - dwPlayCount = 0; - } - -} SAMPLELOOPSTRUCT; - -STATIC_ASSERT(sizeof(SAMPLELOOPSTRUCT) == 24); - - -typedef struct PACKED WAVESAMPLERINFO -{ - WAVESMPLHEADER wsiHdr; - SAMPLELOOPSTRUCT wsiLoops[2]; -} WAVESAMPLERINFO; - -STATIC_ASSERT(sizeof(WAVESAMPLERINFO) == 92); - - -typedef struct PACKED WAVELISTHEADER -{ - DWORD list_id; // "LIST" -> 0x5453494C - DWORD list_len; - DWORD info; // "INFO" -} WAVELISTHEADER; - -STATIC_ASSERT(sizeof(WAVELISTHEADER) == 12); - - -typedef struct PACKED WAVEEXTRAHEADER -{ - DWORD xtra_id; // "xtra" -> 0x61727478 - DWORD xtra_len; - DWORD dwFlags; - WORD wPan; - WORD wVolume; - WORD wGlobalVol; - WORD wReserved; - BYTE nVibType; - BYTE nVibSweep; - BYTE nVibDepth; - BYTE nVibRate; -} WAVEEXTRAHEADER; - -STATIC_ASSERT(sizeof(WAVEEXTRAHEADER) == 24); - - -struct PACKED WavCueHeader -{ - uint32 id; // "cue " -> 0x20657563 - uint32 length; - uint32 numPoints; - - // Convert all multi-byte numeric values to current platform's endianness or vice versa. - void ConvertEndianness() - { - SwapBytesLE(id); - SwapBytesLE(length); - SwapBytesLE(numPoints); - } -}; - -STATIC_ASSERT(sizeof(WavCueHeader) == 12); - - -struct PACKED WavCuePoint -{ - uint32 id; // Unique identification value - uint32 pos; // Play order position - uint32 chunkID; // RIFF ID of corresponding data chunk - uint32 chunkStart; // Byte Offset of Data Chunk - uint32 blockStart; // Byte Offset to sample of First Channel - uint32 offset; // Byte Offset to sample byte of First Channel - - // Convert all multi-byte numeric values to current platform's endianness or vice versa. - void ConvertEndianness() - { - SwapBytesLE(id); - SwapBytesLE(pos); - SwapBytesLE(chunkID); - SwapBytesLE(chunkStart); - SwapBytesLE(blockStart); - SwapBytesLE(offset); - } -}; - -STATIC_ASSERT(sizeof(WavCuePoint) == 24); - - #ifdef NEEDS_PRAGMA_PACK #pragma pack(pop) #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |