VOC File Player

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

  • Goal

    Posted by snareenactina on 11/07/2012 04:06am

    axils The U.S. economy is about to get the Bob Woodward treatment. I try and avoid the chain stores as much as possible, but it’s become nearly impossible here in the city of Boston. I’ve always held a dim view of these large, sterile warehouse kinds of stores. I really miss the little neighborhood stores, which are almost all gone now. After viewing product detail pages or search results, look here to find an easy way to navigate back to pages you are interested in. glucagon If you can't remember the last time you had your car serviced, take it in. In extreme situations, you might increase your mileage by up to 10 percent. So what? Well, if you drove 20,000 miles a year, you would save $250 - enough to cover the cost of the service, buy yourself a super-size falafel sandwich and still have a few bucks left over to start tipping your mechanic. (You did know you're supposed to tip your mechanic, right?) suiko The history of empires past and present is the story of this stripping away of that ability and that right, this violent mangling of the relationships that different peoples have created over time with the places that they live in. lviii Already a member? ridbc Unemployment is a phenomenon when a person is available for work but is not able to get it. The level of unemployment is known as unemployment rate which is a major criterion to check a country's growth rate and macroeconomics. Causes of unemployment always have been controversial and have been debated by many financial experts. Unemployment and its causes change with the location as well. harbaugh Academic and policy interest has now moved beyond simply the optimal commercial exploitation of the standard trio of resources to encompass management for other objectives. For example, natural resources more broadly defined have recreational, as well as commercial values. They may also contribute to overall social welfare levels, by their mere existence. rail The gross domestic product (GDP) has been widely adopted to measure the wealth of a country for a long time. However, actually, it can not comprehensively reflect the economic power of a country and if the countries have been ranked from another perspective, they may be another story. orgstephanie Combined

    Reply
  • 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
  • Loading, Please Wait ...

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

Top White Papers and Webcasts

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds