VOC File Player

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

This article was contributed by Pierre Fournier .

Wave files (.WAV) are very easy to handle with Microsoft compilers. Unfortunately, I had to work with Creative Labs' .VOC audio files which are not directly supported.

Although some documentation say that you simply need to "throw the sound file to the wave mapper which will take care of everything!", it was not that easy. When I was doing so, I was hearing a constant 'pop' in the playback. To solve this problem, I had to extract each data block from the file and get rid of the unwanted data.

VOC files work in blocks. Each of the nine different blocks has its own format. A basic VOC file only uses blocks of type 1, 8 and 9. This is what I had to work with, and this is what my code uses.

The code uses the waveOutxxx() functions. These functions work wonderfully, as long as you provide the correct information to them. The class used to play the VOC file is declared as follow:

class CVocPlayer
{
public:
 CVocPlayer();
 virtual ~CVocPlayer();

 void lay( const CString &rcFileName, CWnd *pCallbackWnd );
 inline void Reset() const        
 { 
  waveOutReset( hWaveOut ); 
 }
 void Clear();

protected:
 char *pData;
 bool boPlaying;

 HWAVEOUT hWaveOut;
 WAVEHDR sWaveHdr;

protected:
 void Decode( const CString &rcFileName, FILEINFO *psFileInfo );
};

Obviously, the function used to play the file is Play(). Notice that a pointer to a window must be specified as a parameter. This window is the one that will be notified when the audio file is done playing, and this step is required to cleanup by calling the Clear() function. There are many ways to let us know when the file is done playing, and this is the one I prefer. Changing the method shouldn't be too hard.

The Decode() function uses a FILEINFO structure. This structure is used to gather information about the audio file required by the device. The structure is defined as follow:

typedef struct
{
   UCHAR       ucBitsPerSample;
   UCHAR       ucChannels;
   USHORT      usFileFormat;
   USHORT      usTimeConstant;
   long        lSamplesPerSeconds;
   long        lTotalLength;
} FILEINFO;

Now, the source code of the Play() function

void CVocPlayer::Play( const CString &rcFileName, CWnd *pCallbackWnd )
{
 Clear();

 // Decode the file
 FILEINFO sFileInfo;
 Decode( rcFileName, &sFileInfo );

 // Prepare a WAVEFORMATEX required for opening the device driver
 WAVEFORMATEX sWaveFormat;
 sWaveFormat.wFormatTag           = WAVE_FORMAT_PCM;
 sWaveFormat.nChannels            = sFileInfo.ucChannels;
 sWaveFormat.nSamplesPerSec       = sFileInfo.lSamplesPerSeconds;
 sWaveFormat.nAvgBytesPerSec      = sFileInfo.lSamplesPerSeconds;
 sWaveFormat.nBlockAlign          = 1;
 sWaveFormat.wBitsPerSample       = sFileInfo.ucBitsPerSample;
 sWaveFormat.cbSize               = sizeof(WAVEFORMATEX);

 // Try to open the device driver
 MMRESULT Result = waveOutOpen( &hWaveOut, WAVE_MAPPER, &sWaveFormat,
 (ULONG)pCallbackWnd->m_hWnd, 0, 
 CALLBACK_WINDOW );
 if ( Result != MMSYSERR_NOERROR )
 {
  hWaveOut = 0;
  return;
 }

 // Prepare the header
 sWaveHdr.lpData            = pData;
 sWaveHdr.dwBufferLength    = sFileInfo.lTotalLength;
 sWaveHdr.dwFlags           = 0;
 sWaveHdr.dwLoops           = 0;
 waveOutPrepareHeader( hWaveOut, &sWaveHdr, sizeof(sWaveHdr) );

 // Play the file
 boPlaying = true;
 waveOutWrite( hWaveOut, &sWaveHdr, sizeof(sWaveHdr) );
}

After decoding the file and storing its information in the FILEINFO structure, we fill the WAVEFORMATEX structure with the appropriate information and give it to the waveOutOpen() function. If the device can handle the wanted format, we prepare the header of the audio output and send our data to the waveOutWrite() function.

To decode the VOC file, we go through each of its blocks and store those we want in a memory buffer (our pData member). At the same time, we fill the FILEINFO structure with the information required by the WAVEFORMATEX structure.

void CVocPlayer::Decode( const CString &rcFileName, FILEINFO *psFileInfo )
{
 // Open the file and allocate the memory
 FILE *pFile = fopen( rcFileName, "rb" );
 long lFileLength = _filelength( _fileno(pFile) );
 pData = new char[ lFileLength ];
 char *pDataPos = pData;

 // Place the file pointer at the beginning of the data
 fseek( pFile, 0x1A, SEEK_SET );

 BYTE bType;
 signed long int lLen;
 do
 {
  // Read the block type
  fread( &bType, sizeof(bType), 1, pFile );

  lLen = 0;
  switch( bType )
  {
   case 1:
   {
    fread( &lLen, 3, 1, pFile );
    lLen -= 2;     // Remove Time Constant and File Format bytes
    fread( &psFileInfo->usTimeConstant, 1, 1, pFile );
    fread( &psFileInfo->usFileFormat, 1, 1, pFile );

    // For the moment, it's a plain 8-bit mono file
    psFileInfo->ucBitsPerSample    = 8;
    psFileInfo->ucChannels         = 1;
    psFileInfo->lSamplesPerSeconds = 1000000 /
    (256-(psFileInfo->usTimeConstant % 256));

    // Store this sample in memory
    fread( pDataPos, lLen, 1, pFile );
    pDataPos += lLen;
    break;
   }

   case 8:
   {
    fseek( pFile, 3, SEEK_CUR );     // Skip the length
    fread( &psFileInfo->usTimeConstant, 2, 1, pFile );
    fread( &psFileInfo->usFileFormat, 1, 1, pFile );
    fread( &psFileInfo->ucChannels, 1, 1, pFile );

    // Block of type 8 is always followed by a block of type 1
    fread( &bType, sizeof(bType), 1, pFile );
    fread( &lLen, 3, 1, pFile );
    lLen -= 2;     // Remove Time Constant and File Format bytes
    fseek( pFile, 2, SEEK_CUR );     // Skip T.C. and F.F.

    psFileInfo->ucBitsPerSample    = 8;
    psFileInfo->ucChannels++;
    psFileInfo->usTimeConstant >>= 8;
    psFileInfo->lSamplesPerSeconds = 1000000 /
    (256-(psFileInfo->usTimeConstant % 256));

    // Store this sample in memory
    fread( pDataPos, lLen, 1, pFile );
    pDataPos += lLen;
    break;
   }

   case 9:
   {
    fread( &lLen, 3, 1, pFile );
    lLen -= 12;
    fread( &psFileInfo->lSamplesPerSeconds, 4, 1, pFile );
    fread( &psFileInfo->ucBitsPerSample, 1, 1, pFile );
    fread( &psFileInfo->ucChannels, 1, 1, pFile );
    fread( &psFileInfo->usFileFormat, 2, 1, pFile );

    // Store this sample in memory
    fread( pDataPos, lLen, 1, pFile );
    pDataPos += lLen;
    break;
   }
  };
 } while ( bType != 0 );

 psFileInfo->lTotalLength = pDataPos-pData;

 fclose( pFile );
}

After the file is played, we need to clean our stuff. The Clear() function takes care of that

void CVocPlayer::Clear()
{
 if ( !boPlaying )
  return;

 waveOutUnprepareHeader( hWaveOut, &sWaveHdr, sizeof(sWaveHdr) );
 delete [] pData;
 pData = NULL;
 waveOutClose( hWaveOut );

 boPlaying = false;
}

...and that's it! All you need to do to play the file is call the Play() function!

Downloads

Download source - 25 KB
Download demo project - 98KB


Comments

  • Help me decode jp2 file format

    Posted by Legacy on 02/11/2003 12:00am

    Originally posted by: Signs

    Please help me decode .jp2 file format for PDA

    Reply
  • VOC can be space compressed

    Posted by Legacy on 11/08/2002 12:00am

    Originally posted by: Dan WInsor

    A voc file can be compressed by including a block type 3.
    The block tells how many bytes should follow with silence.

    Reply
  • WAVE from

    Posted by Legacy on 07/01/2002 12:00am

    Originally posted by: Janakiraman

    The project is Based on BIo-Medical Instrumentation.
    
    Converting Electical Signals as wave form.(ECG).
    Can anybody tell me how to dispaly a wave of Electrical signal.

    I can convert Electrical signals into Sound signals using suitable amplifier.

    Reply
  • Thanks a lot...

    Posted by Legacy on 03/07/2002 12:00am

    Originally posted by: Gerson

    I was looking for informations about wave files... I found it in your page! Thanks a lot. Congratulations...

    Gerson.

    Reply
  • Record .voc file

    Posted by Legacy on 02/18/2002 12:00am

    Originally posted by: Bryan Evenson

    I'm looking to do a project that can record and playback a .voc file. Any suggestions on how to record a .voc file?

    Thanks,
    Bryan

    Reply
  • .CPP파일이 하나 없군요

    Posted by Legacy on 12/11/2001 12:00am

    Originally posted by: BONGSOO

    없는 파일이 하나 있습니다.
    하지만 윗글을 참고 해서 만들면됩니다.

    Reply
  • Anyone looking for VocPlayer.cpp? Here is the way...

    Posted by Legacy on 04/04/2001 12:00am

    Originally posted by: Senel Canik

    To have a VocPlayer.cpp, simply create a new Dialog based MFC project with a name "VocPlayer". Grab the VocPlayer.cpp file just created by MFC and merge with the project supplied by Mr. Pierre Fournier? Good luck.

    Senel Canik
    Aircraft Engineer

    Reply
  • Anyone looking for VocPlayer.cpp? Here is the way...

    Posted by Legacy on 04/03/2001 12:00am

    Originally posted by: Senel Canik

    To have a VocPlayer.cpp, simply create a new Dialog based MFC project with a name "VocPlayer". Grab the VocPlayer.cpp file just created by MFC and merge with the project supplied by Mr. Pierre Fournier? Good luck.

    Senel Canik
    Aircraft Engineer

    Reply
  • help me to process the video image

    Posted by Legacy on 04/12/2000 12:00am

    Originally posted by: Guest

    I need to do video enforcement system. Please help me how to capture the image form the camera to the system in Winnt 4 and visual C++ 6. thank you..
    

    Reply
  • where is vocplayer.cpp

    Posted by Legacy on 01/25/2000 12:00am

    Originally posted by: huangwei

    where is vocplayer.cpp

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date