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

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Information is data with context. The era of Big Data has begun demonstrating to information security that there is more that can, and must, be done to identify threats, reduce risk, address fraud, and improve compliance monitoring activities by bringing better context to data and thereby creating information for actionable intelligence. This analyst report sets the stage and provides insights into IT and information security practitioners' perceptions of the impediments to, and the solutions necessary for, …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds