TX Library Help – Version: 00173a, Revision: 173
 ALL  Windows graphics in a sandbox

TXWave.h

См. документацию.
00001 //{================================================================================================================
00004 //  @mainpage
00020 //              $Copyright: (C) Ded (Ilya Dedinsky, http://txlib.ru) <mail@txlib.ru> $
00021 //-----------------------------------------------------------------------------------------------------------------
00024 //}================================================================================================================
00025 
00026 #ifndef __TXWAVE_INCLUDED
00027 #define __TXWAVE_INCLUDED
00028 
00029 //=================================================================================================================
00030 
00031 #include "TXLib.h"
00032 #include <limits.h>
00033 
00034 #if !(defined (_TX_VER) && (_TX_VER >= 0x173a0105))
00035     #error Must use TXLib.h version >= 1.73a, revision >= 105 to compile TXWave.
00036     #endif
00037 
00038 #if defined (_MSC_VER)
00039     #pragma warning (push)
00040     #pragma warning (disable: 4068)             // Unknown pragma
00041     #pragma warning (disable: 4200)             // Nonstandard extension used: zero-sized array in struct/union
00042     #pragma warning (disable: 28159)            // Consider using 'GetTickCount64' instead of 'GetTickCount'
00043     #endif
00044 
00045 //=================================================================================================================
00046 
00047 #if defined (TX_COMPILED)  &&  defined (TX_COMPILING)
00048     #undef   TX_COMPILED
00049     #endif
00050 
00051 #if !defined (TX_COMPILED) && !defined (TX_COMPILING)
00052 
00053     #define _TX_BEGIN_NAMESPACE                      namespace { namespace TX {
00054     #define _TX_END_NAMESPACE                        } }
00055 
00056 #else
00057 
00058     #define _TX_BEGIN_NAMESPACE                                  namespace TX {
00059     #define _TX_END_NAMESPACE                        }
00060 
00061 #endif
00062 
00063 //=================================================================================================================
00064 
00067 _TX_BEGIN_NAMESPACE
00068 
00071 //{----------------------------------------------------------------------------------------------------------------
00076 //}----------------------------------------------------------------------------------------------------------------
00077 
00078 const double txWaveSampleRate = 44.100;
00079 
00080 //{----------------------------------------------------------------------------------------------------------------
00089 //}----------------------------------------------------------------------------------------------------------------
00090 
00091 const WAVEFORMATEX txWaveFormat = { WAVE_FORMAT_PCM, 2, (DWORD) (txWaveSampleRate*1000),
00092                                                         (DWORD) (txWaveSampleRate*1000) * 2*16/8, 2*16/8, 16 };
00093 
00094 //{----------------------------------------------------------------------------------------------------------------
00100 //}----------------------------------------------------------------------------------------------------------------
00101 
00102 const double txWaveVolMax = ((1 << txWaveFormat.wBitsPerSample) - 1) / 2.0;
00103 
00104 //{----------------------------------------------------------------------------------------------------------------
00124 //}----------------------------------------------------------------------------------------------------------------
00125 
00126 union txWaveSample_t
00127     {
00129 
00130     short ch[2];
00131 
00133 
00134     inline operator short*() { return ch; }
00135     };
00136 
00137 //{----------------------------------------------------------------------------------------------------------------
00163 //}----------------------------------------------------------------------------------------------------------------
00164 
00165 typedef std::vector <txWaveSample_t> txWaveData_t;
00166 
00167 //{----------------------------------------------------------------------------------------------------------------
00231 //}----------------------------------------------------------------------------------------------------------------
00232 
00233 HWAVEOUT txWaveOut (int timeMs = -INT_MAX,
00234                     double freqL =  0, double volL = 50,
00235                     double freqR = -1, double volR = -1,
00236                     int loops = 1,
00237                     const txWaveData_t& data = txWaveData_t());
00238 
00239 //{----------------------------------------------------------------------------------------------------------------
00281 //}----------------------------------------------------------------------------------------------------------------
00282 
00283 HWAVEOUT txWaveOut (const txWaveData_t& data, int loops = 1);
00284 
00285 //{----------------------------------------------------------------------------------------------------------------
00298 //}----------------------------------------------------------------------------------------------------------------
00299 
00300 typedef bool MonitorProc_t (HWAVEIN waveIn, txWaveData_t& data, void* userData);
00301 
00302 //{----------------------------------------------------------------------------------------------------------------
00337 //}----------------------------------------------------------------------------------------------------------------
00338 
00339 #ifdef FOR_DOXYGEN_ONLY
00340 bool MonitorProc (HWAVEIN waveIn, txWaveData_t& data, void* userData);
00341 #endif
00342 
00343 //{----------------------------------------------------------------------------------------------------------------
00369 //}----------------------------------------------------------------------------------------------------------------
00370 
00371 txWaveData_t txWaveIn (int timeMs,
00372                        MonitorProc_t* monitorProc = NULL, void* monitorData = NULL,
00373                        unsigned frameTime = 0);
00374 
00375 //{----------------------------------------------------------------------------------------------------------------
00396 //}----------------------------------------------------------------------------------------------------------------
00397 
00398 unsigned long txWaveGetPosition (void* wave);
00399 
00400 //{----------------------------------------------------------------------------------------------------------------
00422 //}----------------------------------------------------------------------------------------------------------------
00423 
00424 txWaveData_t txWaveLoadWav (const char filename[]);
00425 
00426 //{----------------------------------------------------------------------------------------------------------------
00441 //}----------------------------------------------------------------------------------------------------------------
00442 
00443 bool txWaveSaveWav (const txWaveData_t& data, const char filename[]);
00444 
00445 //{----------------------------------------------------------------------------------------------------------------
00460 //}----------------------------------------------------------------------------------------------------------------
00461 
00462 #define CALLOC( type, size )  ( (type*) calloc ((size), sizeof (type)) )
00463 
00464 //{----------------------------------------------------------------------------------------------------------------
00476 //}----------------------------------------------------------------------------------------------------------------
00477 
00478 #define FREE( ptr )  ( free (ptr), (ptr) = NULL )
00479 
00480 //-----------------------------------------------------------------------------------------------------------------
00481 
00484 _TX_END_NAMESPACE
00485 
00488 //{----------------------------------------------------------------------------------------------------------------
00502 //}----------------------------------------------------------------------------------------------------------------
00503 
00504 inline void* operator new (size_t size, int /* = 0 */) { return ::memset (::new char [size], 0, size); }
00505 
00506 //{----------------------------------------------------------------------------------------------------------------
00521 //}----------------------------------------------------------------------------------------------------------------
00522 
00523 inline void* operator new (size_t size, size_t items, int /* = 0 */) { return ::new (0) char [size * items];         }
00524 
00527 _TX_BEGIN_NAMESPACE
00528 
00531 #if !defined (TX_COMPILED)
00532 
00533 //{================================================================================================================
00534 
00535 namespace Win32
00536 {
00537 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutOpen,            (HWAVEOUT* wave, UINT device, const WAVEFORMATEX* format,
00538                                                            DWORD callback, DWORD callbackData, DWORD flags));
00539 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutPrepareHeader,   (HWAVEOUT wave, WAVEHDR* header, UINT size));
00540 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutUnprepareHeader, (HWAVEOUT wave, WAVEHDR* header, UINT size));
00541 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutWrite,           (HWAVEOUT wave, WAVEHDR* header, UINT size));
00542 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutReset,           (HWAVEOUT wave));
00543 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutClose,           (HWAVEOUT wave));
00544 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutBreakLoop,       (HWAVEOUT wave));
00545 _TX_DLLIMPORT ("WinMM", MMRESULT, waveOutGetPosition,     (HWAVEOUT wave, MMTIME* time, UINT size));
00546 
00547 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInOpen,             (HWAVEIN* wave, UINT device, const WAVEFORMATEX* format,
00548                                                            DWORD callback, DWORD callbackData, DWORD flags));
00549 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInPrepareHeader,    (HWAVEIN wave, WAVEHDR* header, UINT size));
00550 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInUnprepareHeader,  (HWAVEIN wave, WAVEHDR* header, UINT size));
00551 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInAddBuffer,        (HWAVEIN wave, WAVEHDR* header, UINT size));
00552 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInStart,            (HWAVEIN wave));
00553 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInStop,             (HWAVEIN wave));
00554 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInReset,            (HWAVEIN wave));
00555 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInClose,            (HWAVEIN wave));
00556 _TX_DLLIMPORT ("WinMM", MMRESULT, waveInGetPosition,      (HWAVEIN wave, MMTIME* time, UINT size));
00557 }
00558 
00559 //}================================================================================================================
00560 
00561 #if defined (_GCC_VER) && (_GCC_VER < 530)
00562 #pragma GCC system_header
00563 #endif
00564 
00565 int _txWaveInit();
00566 
00567 int _txWaveInitialized = _txWaveInit();
00568 
00569 int _txWaveInit()
00570     {
00571     assert (sizeof (txWaveSample_t)      == txWaveFormat.nBlockAlign);
00572     assert (txWaveFormat.nBlockAlign     == txWaveFormat.wBitsPerSample/8 * txWaveFormat.nChannels);
00573     assert (txWaveFormat.nAvgBytesPerSec == txWaveFormat.nSamplesPerSec   * txWaveFormat.nBlockAlign);
00574 
00575     (void) _txWaveInitialized;
00576     return 1;
00577     }
00578 
00579 //-----------------------------------------------------------------------------------------------------------------
00580 
00581 HWAVEOUT txWaveOut (int timeMs /* = -INT_MAX */,
00582                     double freqL /* =  0 */, double volL /* = 50 */,
00583                     double freqR /* = -1 */, double volR /* = -1 */,
00584                     int loops /* = 1 */,
00585                     const txWaveData_t& data /* = txWaveData_t() */)
00586     {
00587     static HWAVEOUT waveOut = NULL;
00588     static WAVEHDR  waveHdr[8] = {};
00589 
00590     static long long phase[2] = {};
00591 
00592     int time0 = GetTickCount();
00593 
00594     // Check the params
00595 
00596     if (freqR < 0) freqR = freqL;
00597     if (volR  < 0) volR  = volL;
00598 
00599     if (loops == 1) loops = 0;
00600 
00601     // Initialize the wave device
00602 
00603     if (!waveOut)
00604         {
00605         Win32::waveOutOpen (&waveOut, WAVE_MAPPER, &txWaveFormat, 0, 0, 0) == MMSYSERR_NOERROR asserted;
00606         if (!waveOut) return NULL;
00607         }
00608 
00609     // Prepare and start the sound
00610 
00611     if (timeMs && (freqL > 0 || freqR > 0 || data.size()))
00612         {
00613         // Prepare the WAVEHDR
00614 
00615         WAVEHDR wav = {};
00616 
00617         unsigned size = (unsigned) data.size();
00618         if ((freqL > 0 && volL > 0) || (freqR > 0 && volR > 0)) size = ROUND (abs (timeMs) * txWaveSampleRate);
00619 
00620         wav.dwBufferLength = (unsigned) (size * sizeof (txWaveSample_t));
00621         wav.lpData = (char*) malloc (wav.dwBufferLength); assert (wav.lpData);
00622 
00623         wav.dwFlags = loops? (WHDR_BEGINLOOP | WHDR_ENDLOOP) : 0;
00624         wav.dwLoops = loops;
00625 
00626         // Copy raw data
00627 
00628         size_t szPrefill = MIN (size, data.size()) * sizeof (txWaveSample_t);
00629 
00630         if (szPrefill) memcpy (wav.lpData, &data[0], szPrefill);
00631 
00632         // Add harmonic data. All values premultiplied by 360 and converted to integers.
00633 
00634         if (freqL > 0 || freqR > 0)
00635             {
00636             long long time    =   ROUND (360 * abs (timeMs) / 1000.0),
00637                       freq[2] = { ROUND (360 * freqL),
00638                                   ROUND (360 * freqR) },
00639                       vol [2] = { ROUND (360 * volL / 101.0  * (int) txWaveVolMax),
00640                                   ROUND (360 * volR / 101.0  * (int) txWaveVolMax) };
00641 
00642             static const int sinTab[91] = {  0,   6,  13,  19,  25,  31,  38,  44,  50,  56,
00643                                             63,  69,  75,  81,  87,  93,  99, 105, 111, 117,
00644                                            123, 129, 135, 141, 146, 152, 158, 163, 169, 175,
00645                                            180, 185, 191, 196, 201, 206, 212, 217, 222, 227,
00646                                            231, 236, 241, 246, 250, 255, 259, 263, 268, 272,
00647                                            276, 280, 284, 288, 291, 295, 298, 302, 305, 309,
00648                                            312, 315, 318, 321, 324, 326, 329, 331, 334, 336,
00649                                            338, 340, 342, 344, 346, 348, 349, 351, 352, 353,
00650                                            355, 356, 356, 357, 358, 359, 359, 360, 360, 360, 360 };
00651 
00652             txWaveSample_t* buf = (txWaveSample_t*) wav.lpData;
00653 
00654             #pragma GCC diagnostic ignored "-Wconversion"
00655 
00656             #define MAKEDATA_(chan)                                                            \
00657                 {                                                                              \
00658                 for (unsigned i = 0; i < size; i++)                                            \
00659                     {                                                                          \
00660                     int ch = (i < szPrefill)? buf[i].ch[chan] * 129600 : 0;                    \
00661                                                                                                \
00662                     int t  = (phase[chan] + freq[chan] * time * i/size) / 360 % 360;           \
00663                                                                                                \
00664                     int sign = +1;                                                             \
00665                     if (t >= 180) { t = t - 180; sign = -1; }                                  \
00666                     if (t >=  90) { t = 180 - t; }                                             \
00667                                                                                                \
00668                     assert (0 <= t && t < (int) sizearr (sinTab));                             \
00669                                                                                                \
00670                     buf[i].ch[chan] = (short) ((ch + vol[chan] * sign * sinTab [t]) / 129600); \
00671                     }                                                                          \
00672                                                                                                \
00673                 phase[chan] += freq[chan] * time;                                              \
00674                 }
00675 
00676             if (volL > 0 && freqL > 0) MAKEDATA_ (0);
00677             if (volR > 0 && freqR > 0) MAKEDATA_ (1);
00678 
00679             #undef MAKEDATA_
00680             #pragma GCC diagnostic warning "-Wconversion"
00681             }
00682 
00683         // Find free WAVEHDR
00684 
00685         WAVEHDR* next = NULL;
00686 
00687         for (size_t i = 0; ; i = (i+1) % sizearr (waveHdr), Sleep (_txWindowUpdateInterval))
00688             {
00689             if (Win32::waveOutUnprepareHeader (waveOut, &waveHdr[i], sizeof (WAVEHDR)) == MMSYSERR_NOERROR)
00690                 {
00691                 next = &waveHdr[i];  // Free WAVEHDR found
00692                 FREE (next->lpData);
00693                 break;
00694                 }
00695 
00696             if (timeMs < 0 && GetTickCount() - time0 < (unsigned) abs (timeMs))
00697                 break;
00698             }
00699 
00700         // Start the sound
00701 
00702         if (next)
00703             {
00704             std::swap (wav, *next);  // Put the data prepared to queue
00705 
00706             Win32::waveOutPrepareHeader (waveOut, next, sizeof (WAVEHDR)) == MMSYSERR_NOERROR asserted;
00707             Win32::waveOutWrite         (waveOut, next, sizeof (WAVEHDR)) == MMSYSERR_NOERROR asserted;
00708 
00709             Win32::waveOutBreakLoop     (waveOut)                         == MMSYSERR_NOERROR asserted;
00710             }
00711         }
00712 
00713     // Wait and stop the sound
00714 
00715     if (timeMs <= 0)
00716         {
00717         if (!timeMs) Win32::waveOutReset (waveOut) == MMSYSERR_NOERROR asserted;  // Immediate stop
00718 
00719         // Wait for sound to stop
00720 
00721         for (size_t i = 0; i < sizearr (waveHdr); i++, Sleep (_txWindowUpdateInterval))
00722             {
00723             if (GetTickCount() - time0 >= (unsigned) abs (timeMs)) break;
00724 
00725             if ((waveHdr[i].dwFlags & WHDR_PREPARED) && !(waveHdr[i].dwFlags & WHDR_DONE)) { i--; continue; }
00726             }
00727 
00728         Win32::waveOutReset (waveOut) == MMSYSERR_NOERROR asserted;
00729 
00730         // Free the buffers
00731 
00732         for (size_t i = 0; i < sizearr (waveHdr); i++)
00733             {
00734             Win32::waveOutUnprepareHeader (waveOut, &waveHdr[i], sizeof (WAVEHDR));
00735             FREE (waveHdr[i].lpData);
00736             }
00737 
00738         // Close the wave device
00739 
00740         Win32::waveOutClose (waveOut) == MMSYSERR_NOERROR asserted;
00741         waveOut = NULL;
00742         }
00743 
00744     return waveOut;
00745     }
00746 
00747 //-----------------------------------------------------------------------------------------------------------------
00748 
00749 HWAVEOUT txWaveOut (const txWaveData_t& data, int loops /* = 1 */)
00750     {
00751     return txWaveOut (-INT_MAX, 0,0,0,0, loops, data);
00752     }
00753 
00754 //-----------------------------------------------------------------------------------------------------------------
00755 
00756 txWaveData_t txWaveIn (int timeMs,
00757                        MonitorProc_t monitorProc /* = NULL */, void* userData /* = NULL */,
00758                        unsigned frameTime /* = 0 */)
00759     {
00760     static HWAVEIN waveIn = NULL;
00761     static WAVEHDR waveHdr[2] = {};
00762 
00763     txWaveData_t data;
00764 
00765     int time0 = GetTickCount();
00766 
00767     // Initialize the wave device
00768 
00769     if (!waveIn)
00770         {
00771         Win32::waveInOpen (&waveIn, WAVE_MAPPER, &txWaveFormat, 0, 0, 0) == MMSYSERR_NOERROR asserted;
00772         if (!waveIn) return data;
00773         }
00774 
00775     // Calculate the sizes
00776 
00777     if (!frameTime) frameTime = 100;  // Default frame time
00778 
00779     unsigned size  = ROUND (abs (timeMs) * txWaveSampleRate);
00780     unsigned frame = ROUND (frameTime    * txWaveSampleRate);
00781 
00782     // Feed the recording queue with buffers
00783 
00784     for (unsigned i = 0; i < sizearr (waveHdr); i++)
00785         {
00786         waveHdr[i].dwBufferLength = frame * (unsigned) sizeof (txWaveSample_t);
00787         waveHdr[i].lpData = (char*) malloc (waveHdr[i].dwBufferLength); assert (waveHdr[i].lpData);
00788 
00789         Win32::waveInPrepareHeader (waveIn, &waveHdr[i], sizeof (waveHdr[i])) == MMSYSERR_NOERROR asserted;
00790         Win32::waveInAddBuffer     (waveIn, &waveHdr[i], sizeof (waveHdr[i])) == MMSYSERR_NOERROR asserted;
00791         }
00792 
00793     // Start the recording
00794 
00795     data.resize (size);
00796     txWaveData_t (data) .swap (data);  // C++11: data.shrink_to_fit();
00797     data.resize (0);
00798 
00799     Win32::waveInStart (waveIn) == MMSYSERR_NOERROR asserted;
00800 
00801     // Recording loop
00802 
00803     for (size_t i = 0; ; i = (i+1) % sizearr (waveHdr), Sleep (_txWindowUpdateInterval))
00804         {
00805         WAVEHDR* wav = &waveHdr[i];
00806 
00807         if (!(wav->dwFlags & WHDR_DONE)) continue;  // Buffer is not done yet
00808 
00809         // Process the buffer recorded
00810 
00811         size_t pos = data.size();
00812         data.resize (pos + MIN (wav->dwBytesRecorded / sizeof (txWaveSample_t), size - pos));
00813 
00814         memcpy (&data[0] + pos, wav->lpData, (data.size() - pos) * sizeof (txWaveSample_t));
00815 
00816         if (monitorProc && !monitorProc (waveIn, data, userData)) break;             // Monitor breaks the recording
00817 
00818         if (timeMs < 0 && GetTickCount() - time0 >= (unsigned) abs (timeMs)) break;  // Time is over
00819 
00820         if (data.size() == size) break;                                              // All data recorded
00821 
00822         // Re-feed the queue with the buffer
00823 
00824         wav->dwFlags         = 0;
00825         wav->dwBytesRecorded = 0;
00826 
00827         Win32::waveInPrepareHeader (waveIn, wav, sizeof (*wav)) == MMSYSERR_NOERROR asserted;
00828         Win32::waveInAddBuffer     (waveIn, wav, sizeof (*wav)) == MMSYSERR_NOERROR asserted;
00829         }
00830 
00831     // Stop the recording
00832 
00833     Win32::waveInStop  (waveIn) == MMSYSERR_NOERROR asserted;
00834     Win32::waveInReset (waveIn) == MMSYSERR_NOERROR asserted;
00835 
00836     // Free the buffers
00837 
00838     for (unsigned i = 0; i < sizearr (waveHdr); i++)
00839         {
00840         Win32::waveInUnprepareHeader (waveIn, &waveHdr[i], sizeof (waveHdr[i])) == MMSYSERR_NOERROR asserted;
00841         FREE (waveHdr[i].lpData);
00842         }
00843 
00844     // Close the wave device
00845 
00846     Win32::waveInClose (waveIn) == MMSYSERR_NOERROR asserted;
00847     waveIn = NULL;
00848 
00849     return data;
00850     }
00851 
00852 //-----------------------------------------------------------------------------------------------------------------
00853 
00854 unsigned long txWaveGetPosition (void* wave)
00855     {
00856     static MMTIME time = { TIME_SAMPLES };
00857 
00858     if (Win32::waveOutGetPosition ((HWAVEOUT) wave, &time, sizeof (time)) == MMSYSERR_NOERROR) return (long) time.u.sample;
00859     if (Win32::waveInGetPosition  ((HWAVEIN)  wave, &time, sizeof (time)) == MMSYSERR_NOERROR) return (long) time.u.sample;
00860 
00861     return ULONG_MAX;
00862     }
00863 
00864 //-----------------------------------------------------------------------------------------------------------------
00865 
00866 struct WAVFILEHEADER
00867     {
00868     unsigned       chunkId;        // 0x46464952 'RIFF'
00869     unsigned long  chunkSize;      // FileSize - sizeof (chunkId) - sizeof (chunkSize)
00870     unsigned       format;         // 0x45564157 'WAVE'
00871 
00872     unsigned       subchunk1Id;    // 0x20746d66 'fmt '
00873     unsigned long  subchunk1Size;  // sizeof (PCMWAVEFORMAT), maybe +2, see below
00874 
00875     PCMWAVEFORMAT  pcm;
00876 
00877     /*                             // Here lies metadata, we ignore them
00878 
00879     struct                         // If (subchunk1Size == sizeof (PCMWAVEFORMAT) + 2)
00880         {
00881         unsigned short size;
00882         unsigned char  data[];     // data [size]
00883         }
00884         metadata[];
00885 
00886     */
00887 
00888     unsigned       subchunk2Id;    // 0x61746164 'data'
00889     unsigned long  subchunk2Size;  // length (numSamples * pcm.wf.nChannels * pcm.wBitsPerSample/8
00890 
00891     txWaveSample_t data[];         // data [numSamples], size in bytes = subchunk2Size
00892     };
00893 
00894 //-----------------------------------------------------------------------------------------------------------------
00895 
00896 #define TRY        int __error = 0;
00897 #define FAIL(err)  { __error = (err); goto __catch; }
00898 #define FAILURE    FAIL (__LINE__)
00899 #define CATCH      __catch: if (__error)
00900 
00901 //-----------------------------------------------------------------------------------------------------------------
00902 
00903 txWaveData_t txWaveLoadWav (const char filename[])
00904     {
00905     assert (filename);
00906 
00907     FILE* f = NULL;
00908     txWaveData_t data;
00909 
00910     TRY
00911         {
00912         // Open the file
00913 
00914         fopen_s (&f, filename, "rb");
00915         if (!f) FAILURE;
00916 
00917         long size = _filelength (_fileno (f));
00918 
00919         // Allocate memory for waveform data
00920 
00921         try { data.resize (size / sizeof (txWaveSample_t)); }
00922         catch (...) { FAILURE; }
00923 
00924         // Read the file header
00925 
00926         WAVFILEHEADER* wav = (WAVFILEHEADER*) &data[0];
00927         fread (wav, sizeof (WAVFILEHEADER), 1, f) == 1 asserted;
00928 
00929         // Check file format and properties
00930 
00931         if (wav->chunkId                != 0x46464952 /* 'RIFF' */)      FAILURE;
00932         if (wav->format                 != 0x45564157 /* 'WAVE' */)      FAILURE;
00933         if (wav->subchunk1Id            != 0x20746d66 /* 'fmt ' */)      FAILURE;
00934 
00935         if (wav->pcm.wf.wFormatTag      != txWaveFormat.wFormatTag)      FAILURE;
00936         if (wav->pcm.wf.nChannels       != txWaveFormat.nChannels)       FAILURE;
00937         if (wav->pcm.wf.nSamplesPerSec  != txWaveFormat.nSamplesPerSec)  FAILURE;
00938         if (wav->pcm.wf.nAvgBytesPerSec != txWaveFormat.nAvgBytesPerSec) FAILURE;
00939         if (wav->pcm.wf.nBlockAlign     != txWaveFormat.nBlockAlign)     FAILURE;
00940 
00941         if (wav->pcm.wBitsPerSample     != txWaveFormat.wBitsPerSample)  FAILURE;
00942 
00943         // Skip metadata
00944 
00945         unsigned metaSize = (wav->subchunk1Size == sizeof (PCMWAVEFORMAT) + 2)? *(short*)&wav->subchunk2Id : 0;
00946         fread (&wav->subchunk2Id, 1, metaSize, f) == metaSize asserted;
00947 
00948         // Now we at waveform data section
00949         
00950         if (wav->subchunk2Id != 0x61746164 /* 'data' */) FAILURE;
00951 
00952         // Read the waveform data
00953 
00954         size -= (long) sizeof (WAVFILEHEADER) + metaSize;
00955         fread (wav, size, 1, f) == 1 asserted;
00956 
00957         // Adjust vector size according to the data read
00958 
00959         data.resize (size / sizeof (txWaveSample_t));
00960         }
00961 
00962     CATCH
00963         {
00964         txNotifyIcon (NIIF_ERROR, "txWaveLoadWav() сообщает", "\nОшибка чтения WAV-файла \"%s\"\n\n"
00965                                                               "См. %s, строку %d", filename, __FILE__, __error);
00966         }
00967 
00968     if (f) fclose (f) == 0 asserted;
00969 
00970     return data;
00971     }
00972 
00973 //-----------------------------------------------------------------------------------------------------------------
00974 
00975 bool txWaveSaveWav (const txWaveData_t& data, const char filename[])
00976     {
00977     assert (filename);
00978 
00979     unsigned size = (unsigned) (data.size() * sizeof (txWaveSample_t));
00980 
00981     WAVFILEHEADER header = { 0x46464952 /* 'RIFF' */,
00982                              (unsigned) (sizeof (header) + size - sizeof (header.chunkId) - sizeof (header.chunkSize)),
00983                              0x45564157 /* 'WAVE' */,
00984 
00985                              0x20746d66 /* 'fmt ' */,
00986                              sizeof (PCMWAVEFORMAT),
00987 
00988                              {{txWaveFormat.wFormatTag,     txWaveFormat.nChannels,
00989                                txWaveFormat.nSamplesPerSec, txWaveFormat.nAvgBytesPerSec,
00990                                txWaveFormat.nBlockAlign},   txWaveFormat.wBitsPerSample},
00991 
00992                              // Here should be metadata, we live happy without them
00993                              
00994                              0x61746164 /* 'data' */,
00995                              size
00996                              };
00997 
00998     FILE* f = NULL;
00999     fopen_s (&f, filename, "wb");
01000     if (!f) return false;
01001 
01002     fwrite (&header,  sizeof (header), 1, f) == 1 asserted;
01003     fwrite (&data[0], size,            1, f) == 1 asserted;
01004 
01005     fclose (f) == 0 asserted;
01006 
01007     return true;
01008     }
01009 
01010 //-----------------------------------------------------------------------------------------------------------------
01011 
01012 #endif
01013 
01016 _TX_END_NAMESPACE
01017 
01020 //=================================================================================================================
01021 
01022 #if defined (_MSC_VER)
01023     #pragma warning (pop)
01024     #endif
01025 
01026 //=================================================================================================================
01027 
01028 #endif  // __TXWAVE_INCLUDED