0
0

hi,

the wave writer in the examples seems to have some inconformity with common wave format spec. so i wrote a handy c++ class for writing wave files given a std::vector or std::queue containing the sound samples.

brett: if you are interested feel free to add it to the examples collection ๐Ÿ˜‰

header file (wavewriter.h):
[code:2dis13ua]

/****************************************************************
* YAG2002 (http://yag2002.sourceforge.net)
* Copyright (C) 2005-2006, A. Botorabi
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
****************************************************************/

/###############################################################
# utilitiy for writing a wave file given a collection of samples
#
# date of creation: 03/18/2006
#
# author: ali botorabi (boto)
# e-mail: botorabi@gmx.net
#
################################################################
/

ifndef WAVEWRITER_H

define WAVEWRITER_H

//! Class for writing a wav file given a collection of samples
//! For PCM16 set DataTypeT to ‘short’
template< typename DataTypeT >
class WaveWriter
{
public:

    //! Channel modes
    enum
    {
        MONO,
        STEREO
    } ChannelMode;

    //! Sample rate can be 8000 or 16000, etc.
    //! Use MONO or STEREO for channelmode
                                                WaveWriter( unsigned samplerate, unsigned int channelmode );

    virtual                                     ~WaveWriter();

    //! Write out the content of vector into given file
    bool                                        write( const std::string&amp; filename, const std::vector&lt; DataTypeT &gt;&amp; data );

    //! Write out the content of queue into given file
    bool                                        write( const std::string&amp; filename, const std::queue&lt; DataTypeT &gt;&amp; data );

protected:

    void                                        writeHeader( std::fstream&amp; stream, unsigned int size );

    void                                        writeSample( std::fstream&amp; stream, DataTypeT sample );

    unsigned int                                _rate;

    unsigned int                                _bits;

    unsigned int                                _channels;

};

//! Define common PCM types for WaveWriter
typedef class WaveWriter< short > WaveWriterPCM16;
typedef class WaveWriter< char > WaveWriterPCM8;

//! Include the inline file

include "wavewriter.inl"

endif // WAVEWRITER_H

[/code:2dis13ua]

inline file (wavewriter.inl):
[code:2dis13ua]
/****************************************************************
* YAG2002 (http://yag2002.sourceforge.net)
* Copyright (C) 2005-2006, A. Botorabi
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
****************************************************************/

/###############################################################
# utilitiy for writing a wave file given a collection of samples
#
# date of creation: 03/18/2006
#
# author: ali botorabi (boto)
# e-mail: botorabi@gmx.net
#
################################################################
/

ifndef WAVEWRITER_H

error "do not include this file directly, include wavewriter.h instead"

endif

template< typename DataTypeT >
WaveWriter< DataTypeT >::WaveWriter( unsigned samplerate, unsigned int channelmode ) :
_rate( samplerate )
{
assert( ( channelmode == WaveWriter::MONO ) || ( channelmode == WaveWriter::STEREO ) && "wrong channel mode!" );

if ( channelmode == MONO )
    _channels = 1;
else
    _channels = 2;

_bits = sizeof( DataTypeT ) * 8;

}

template< typename DataTypeT >
WaveWriter< DataTypeT >::~WaveWriter()
{
}

template< typename DataTypeT >
void WaveWriter< DataTypeT >::writeHeader( std::fstream& stream, unsigned int size )
{
typedef struct
{
char _id[ 4 ]; /* "RIFF" */
int _size;
char _formatTag[ 4 ]; /* format type "WAVE" */
} RiffChunk;

typedef struct 
{
    char            _subChunk1ID[ 4 ];      /* &quot;fmt &quot; */
    unsigned int    _subChunk1Size;         /* 16 for PCM  */
    unsigned short  _audioFormat;           /* 1 for PCM  */
    unsigned short  _channels;              /* number of channels (i.e. mono, stereo...)  */
    unsigned int    _samplesPerSec;         /* sample rate  */
    unsigned int    _avgBytesPerSec;        /* for buffer estimation  */
    unsigned short  _blockAlign;            /* block size of data  */
    unsigned short  _bitsPerSample;         /* number of bits per sample of mono data */
} FmtChunk;

typedef struct 
{
    char            _subChunk2ID[ 4 ];      /* &quot;data&quot; */
    unsigned int    _subChunk2Size;
} DataChunk;

typedef struct
{
    RiffChunk       _riffchunk;
    FmtChunk        _fmtchunk;
    DataChunk       _datachunk;
} WavHeader;

WavHeader header;
// fill in the RIFF chunk
strcpy( header._riffchunk._id, &quot;RIFF&quot; );
header._riffchunk._size = 36 + _rate * _channels * _bits / 8;
strcpy( header._riffchunk._formatTag, &quot;WAVE&quot; );
// fill in the subchunk 1
strcpy( header._fmtchunk._subChunk1ID, &quot;fmt &quot; );
header._fmtchunk._subChunk1Size  = 16; // 16 for PCM
header._fmtchunk._audioFormat    = 1;  // 1  for PCM
header._fmtchunk._channels       = _channels;
header._fmtchunk._samplesPerSec  = _rate;
header._fmtchunk._avgBytesPerSec = _rate * _channels * _bits / 8;
header._fmtchunk._blockAlign     = _channels * _bits / 8;
header._fmtchunk._bitsPerSample  = _bits;
// fill in the subchunk 2
strcpy( header._datachunk._subChunk2ID, &quot;data&quot; );
header._datachunk._subChunk2Size = size * _channels * _bits / 8;

// write out the header
char* p_buffer = reinterpret_cast&lt; char* &gt;( &amp;header );
unsigned int headersize = sizeof( header );
for ( unsigned int cnt = 0; cnt &lt; headersize; ++cnt )
    stream &lt;&lt; p_buffer[ cnt ];

}

template< typename DataTypeT >
void WaveWriter< DataTypeT >::writeSample( std::fstream& stream, DataTypeT sample )
{
// write out one single sample
unsigned int mask = 0xff;
unsigned int datasize = sizeof( DataTypeT );
for ( unsigned int bytes = 0; bytes < datasize; ++bytes )
{
char c = static_cast< char >( ( sample & mask ) >> ( 8 * bytes ) );
stream << c;
mask = mask << 8;
}
}

template< typename DataTypeT >
bool WaveWriter< DataTypeT >::write( const std::string& filename, const std::vector< DataTypeT >& data )
{
std::fstream file;

file.open( filename.c_str(), std::ios_base::out | std::ios_base::binary );
if ( !file )
    return false;

writeHeader( file, data.size() );

std::vector&lt; DataTypeT &gt;::const_iterator p_beg = data.begin(), p_end = data.end();
for ( ; p_beg != p_end; ++p_beg )
    writeSample( file, *p_beg );

file.close();

return true;

}

template< typename DataTypeT >
bool WaveWriter< DataTypeT >::write( const std::string& filename, const std::queue< DataTypeT >& data )
{
std::fstream file;
file.open( filename.c_str(), std::ios_base::out | std::ios_base::binary );
if ( !file )
return false;

writeHeader( file, data.size() );

// write out the samples
std::queue&lt; DataTypeT &gt; tmpqueue( data );
while ( !tmpqueue.empty() )
{
    writeSample( file, tmpqueue.front() );
    tmpqueue.pop();
}

file.close();

return true;

}
[/code:2dis13ua]

example for usage:
[code:2dis13ua]

std::queue&lt; short or char ( see below ) &gt; samples;
// fill in samples into queue
......

  or

std::vector&lt; short or char ( see below ) &gt; samples;
// fill in samples into vector
.......

// write out the wave file, PCM16, 16khz, mono
WaveWriterPCM16 wavwriter( 16000, WaveWriterPCM16::MONO );
if ( !wavwriter.write( &quot;C:\\temp\\myfile.wav&quot;, samples ) )
    std::cout &lt;&lt; &quot;cannot create wave file&quot; &lt;&lt; std::endl;

  or

// write out the wave file, PCM8, 8khz, stereo
WaveWriterPCM8 wavwriter( 8000, WaveWriterPCM8::STEREO );
if ( !wavwriter.write( &quot;C:\\temp\\myfile.wav&quot;, samples ) )
    std::cout &lt;&lt; &quot;cannot create wave file&quot; &lt;&lt; std::endl;

[/code:2dis13ua]

cheers
boto

  • You must to post comments
0
0

hi brett,

the generated wave files could not be played in some applications, only winamp was able to play them and the files were played in doubled speed in winamp.

concerning the licensing of the utility code, do not care about my licensing note; the code is a gift, so you can remove the licensing note ๐Ÿ˜‰

cheers
boto

  • You must to post comments
Showing 1 result
Your Answer

Please first to submit.