4 * WAV file I/O channel class.
6 * Portable Windows Library
8 * Copyright (c) 2001 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is
23 * Roger Hardiman <roger@freebsd.org>
24 * and Shawn Pai-Hsiang Hsiao <shawn@eecs.harvard.edu>
26 * All Rights Reserved.
28 * Contributor(s): ______________________________________.
31 * Revision 1.14 2004/07/15 03:12:41 csoutheren
32 * Migrated changes from crs_vxnml_devel branch into main trunk
34 * Revision 1.13.4.4 2004/07/13 08:13:04 csoutheren
35 * Lots of implementation of factory-based PWAVFile
37 * Revision 1.13.4.3 2004/07/12 09:17:19 csoutheren
38 * Fixed warnings and errors under Linux
40 * Revision 1.13.4.2 2004/07/12 08:30:16 csoutheren
41 * More fixes for abstract factory implementation of PWAVFile
43 * Revision 1.13.4.1 2004/07/07 07:07:41 csoutheren
44 * Changed PWAVFile to use abstract factories (extensively)
45 * Removed redundant blocking/unblocking when using G.723.1
46 * More support for call transfer
48 * Revision 1.13 2003/03/07 06:12:05 robertj
49 * Added more WAV file "magic numbers".
51 * Revision 1.12 2002/09/16 01:08:59 robertj
52 * Added #define so can select if #pragma interface/implementation is used on
53 * platform basis (eg MacOS) rather than compiler, thanks Robert Monaghan.
55 * Revision 1.11 2002/06/20 00:51:38 craigs
56 * Added virtuals to allow overriding
58 * Revision 1.10 2002/05/21 01:56:53 robertj
59 * Removed the enum which made yet another set of magic numbers for audio
60 * formats, now uses the WAV file format numbers.
61 * Fixed failure to write header when destroying object without and explicit
63 * Fixed missing Open() function which does not have file name parameter.
64 * Added ability to set the audio format after construction.
66 * Revision 1.9 2002/01/22 03:55:07 craigs
67 * Added #define guards when file moved to PTCLib
69 * Revision 1.8 2002/01/13 21:00:41 rogerh
70 * The type of new .WAV files must now be specified in the class constructor.
71 * Take out Open() function from the last commit and create a new Open()
72 * function which replaces the one in the PFile base class.
74 * Revision 1.7 2002/01/11 16:33:46 rogerh
75 * Create a PWAVFile Open() function, which processes the WAV header
77 * Revision 1.6 2001/10/16 13:27:37 rogerh
78 * Add support for writing G.723.1 WAV files.
79 * MS Windows can play G.723.1 WAV Files in Media Player and Sound Recorder.
80 * Sound Recorder can also convert them to normal PCM format WAV files.
81 * Thanks go to M.Stoychev <M.Stoychev@cnsys.bg> for sample WAV files.
83 * Revision 1.5 2001/10/15 11:48:15 rogerh
84 * Add GetFormat to return the format of a WAV file
86 * Revision 1.4 2001/07/23 01:20:20 rogerh
87 * Add updates from Shawn - ensure isvalidWAV is false for zero length files.
88 * GetDataLength uses actual file size to support file updates as well as appends.
89 * Add updates from Roger - Update Header() just writes to specific fields which
90 * preserves any 'extra' data in an existing header between FORMAT and DATA chunks.
92 * Revision 1.3 2001/07/20 07:06:27 rogerh
95 * Revision 1.2 2001/07/20 03:30:59 robertj
96 * Minor cosmetic changes to new PWAVFile class.
98 * Revision 1.1 2001/07/19 09:55:48 rogerh
99 * Add PWAVFile, a class to read and write .wav files, written by
100 * Roger Hardiman and <roger@freebsd.org> and
101 * Shawn Pai-Hsiang Hsiao <shawn@eecs.harvard.edu>
109 //#ifdef P_USE_PRAGMA
118 #define P_PACKED __attribute__ ((packed));
126 char tag
[4] P_PACKED
;
127 PInt32l len P_PACKED
;
130 struct RIFFChunkHeader
132 ChunkHeader hdr P_PACKED
;
133 char tag
[4] P_PACKED
;
138 ChunkHeader hdr P_PACKED
; // chunk header
139 PUInt16l format P_PACKED
; // Format
140 PUInt16l numChannels P_PACKED
; // Channels 0x01 = mono, 0x02 = stereo
141 PUInt32l sampleRate P_PACKED
; // Sample Rate in Hz
142 PUInt32l bytesPerSec P_PACKED
; // Average bytes Per Second
143 PUInt16l bytesPerSample P_PACKED
; // Bytes Per Sample, eg 2
144 PUInt16l bitsPerSample P_PACKED
; // Bits Per Sample, eg 16
156 * abstract factory class for handling WAV files formats
162 * return a PWAVFile format code
164 virtual unsigned GetFormat() const = 0;
167 * return a string that can be used as a media format
169 virtual PString
GetFormatString() const = 0;
172 * return a string that can be used as a text description
174 virtual PString
GetDescription() const = 0;
177 * populate the header with the correct values
179 virtual void CreateHeader(PWAV::FMTChunk
& header
, PBYTEArray
& extendedHeader
) = 0;
182 * write any extra headers after the FORMAT chunk
184 virtual BOOL
WriteExtraChunks(PWAVFile
& /*file*/)
188 * read any extra headers after the FORMAT chunk
190 virtual BOOL
ReadExtraChunks(PWAVFile
& /*file*/)
194 * called before the reading/writing starts
196 virtual void OnStart()
200 * called after the reading/writing stops
202 virtual void OnStop()
206 * write data to the file
208 virtual BOOL
Read(PWAVFile
& file
, void * buf
, PINDEX
& len
);
211 * read data from the file
213 virtual BOOL
Write(PWAVFile
& file
, const void * buf
, PINDEX
& len
);
216 typedef PFactory
<PWAVFileFormat
> PWAVFileFormatByFormatFactory
;
217 typedef PFactory
<PWAVFileFormat
, unsigned> PWAVFileFormatByIDFactory
;
220 * abstract factory class for autoconversion of WAV files to/from PCM-16
222 class PWAVFileConverter
225 virtual unsigned GetFormat (const PWAVFile
& file
) const = 0;
226 virtual off_t
GetPosition (const PWAVFile
& file
) const = 0;
227 virtual BOOL
SetPosition (PWAVFile
& file
, off_t pos
, PFile::FilePositionOrigin origin
) = 0;
228 virtual unsigned GetSampleSize(const PWAVFile
& file
) const = 0;
229 virtual off_t
GetDataLength (PWAVFile
& file
) = 0;
230 virtual BOOL
Read (PWAVFile
& file
, void * buf
, PINDEX len
) = 0;
231 virtual BOOL
Write (PWAVFile
& file
, const void * buf
, PINDEX len
) = 0;
234 typedef PFactory
<PWAVFileConverter
, unsigned> PWAVFileConverterFactory
;
236 /**A class representing a WAV audio file.
238 class PWAVFile
: public PFile
240 PCLASSINFO(PWAVFile
, PFile
);
243 /**@name Construction */
245 /**When a file is opened for writing, we can specify if this is a PCM
246 wav file or a G.723.1 wav file.
249 fmt_PCM
= 1, /// PCM, 8kHz, 16 bit, mono
250 fmt_ALaw
= 6, /// A-Law 8kHz
251 fmt_uLaw
= 7, /// u-Law 8kHz
252 fmt_GSM
= 0x31, /// GSM
253 fmt_G728
= 0x41, /// RFC2361
254 fmt_G723
= 0x42, /// RFC2361
255 fmt_MSG7231
= 0x42, /// Microsoft G.723.1
256 fmt_G726
= 0x64, /// RFC2361
257 fmt_G722
= 0x65, /// RFC2361
258 fmt_G729
= 0x84, /// RFC2361
259 fmt_VivoG7231
= 0x111, /// VivoActive G.723.1
261 // For backward compatibility
262 PCM_WavFile
= fmt_PCM
,
263 G7231_WavFile
= fmt_VivoG7231
,
265 // allow opening files without knowing the format
266 fmt_NotKnown
= 0x10000
269 /**Create a WAV file object but do not open it. It does not
270 initially have a valid file name. However, an attempt to open the file
271 using the #PFile::Open()# function will generate a unique
274 If a WAV file is being created, the type parameter can be used
275 to create a PCM Wave file or a G.723.1 Wave file by using
279 unsigned format
= fmt_PCM
/// Type of WAV File to create
281 static PWAVFile
* format(
282 const PString
& format
/// Type of WAV File to create
285 /**Create a unique temporary file name, and open the file in the specified
286 mode and using the specified options. Note that opening a new, unique,
287 temporary file name in ReadOnly mode will always fail. This would only
288 be usefull in a mode and options that will create the file.
290 If a WAV file is being created, the type parameter can be used
291 to create a PCM Wave file or a G.723.1 Wave file by using
294 The #PChannel::IsOpen()# function may be used after object
295 construction to determine if the file was successfully opened.
298 OpenMode mode
, /// Mode in which to open the file.
299 int opts
= ModeDefault
, /// #OpenOptions enum# for open operation.
300 unsigned format
= fmt_PCM
/// Type of WAV File to create
302 static PWAVFile
* format(
303 const PString
& format
, /// Type of WAV File to create
304 PFile::OpenMode mode
, /// Mode in which to open the file.
305 int opts
= PFile::ModeDefault
/// #OpenOptions enum# for open operation.
308 /**Create a WAV file object with the specified name and open it in
309 the specified mode and with the specified options.
310 If a WAV file is being created, the type parameter can be used
311 to create a PCM Wave file or a G.723.1 Wave file by using
314 The #PChannel::IsOpen()# function may be used after object
315 construction to determine if the file was successfully opened.
318 const PFilePath
& name
, /// Name of file to open.
319 OpenMode mode
= ReadWrite
, /// Mode in which to open the file.
320 int opts
= ModeDefault
, /// #OpenOptions enum# for open operation.
321 unsigned format
= fmt_PCM
/// Type of WAV File to create
324 const PString
& format
, /// Type of WAV File to create
325 const PFilePath
& name
, /// Name of file to open.
326 OpenMode mode
= PFile::ReadWrite
, /// Mode in which to open the file.
327 int opts
= PFile::ModeDefault
/// #OpenOptions enum# for open operation.
330 /**Close the file before destruction.
332 ~PWAVFile() { Close(); }
335 /**@name Overrides from class PFile */
337 /**Call PFile::Read() to read in audio data and perform necessary
338 processing such as byte-order swaping.
341 TRUE indicates that at least one character was read from the channel.
342 FALSE means no bytes were read due to timeout or some other I/O error.
345 void * buf
, /// Pointer to a block of memory to receive the read bytes.
346 PINDEX len
/// Maximum number of bytes to read into the buffer.
349 /**Call PFile::Write() to write out audio data and perform necessary
350 processing such as byte-order swaping.
353 TRUE indicates that at least one character was written to the channel.
354 FALSE means no bytes were written due to timeout or some other I/O error.
357 const void * buf
, /// Pointer to a block of memory to receive the write bytes.
358 PINDEX len
/// Maximum number of bytes to write to the channel.
361 /**Open the current file in the specified mode and with
362 the specified options. If the file object already has an open file then
365 If there has not been a filename attached to the file object (via
366 #SetFilePath()#, the #name# parameter or a previous
367 open) then a new unique temporary filename is generated.
370 TRUE if the file was successfully opened.
373 OpenMode mode
= ReadWrite
, // Mode in which to open the file.
374 int opts
= ModeDefault
// Options for open operation.
377 /**Open the specified WAV file name in the specified mode and with
378 the specified options. If the file object already has an open file then
380 This reads (and validates) the header for existing files.
381 For new files, it creates a new file (and header) using the type of
382 WAV file specified in the class constructor.
384 Note: if #mode# is StandardInput, StandardOutput or StandardError,
385 then the #name# parameter is ignored.
388 TRUE if the file was successfully opened.
391 const PFilePath
& name
, // Name of file to open.
392 OpenMode mode
= ReadWrite
, // Mode in which to open the file.
393 int opts
= ModeDefault
// #OpenOptions enum# for open operation.
396 /** Close the file channel.
397 If a WAV file has been written to, this will update the header
398 to contain the correct size information.
399 @return TRUE if close was OK.
401 virtual BOOL
Close();
403 /**Set the current active position in the file for the next read or write
404 operation. The #pos# variable is a signed number which is
405 added to the specified origin. For #origin == PFile::Start#
406 only positive values for #pos# are meaningful. For
407 #origin == PFile::End# only negative values for
408 #pos# are meaningful.
410 Note that for a WAV file, the origin of the file is right after
411 the header. That is, the WAV header is not included when
412 perform SetPosition().
415 TRUE if the new file position was set.
417 virtual BOOL
SetPosition(
418 off_t pos
, /// New position to set.
419 FilePositionOrigin origin
= Start
/// Origin for position change.
422 /**Get the current active position in the file for the next read
423 or write operation. The WAV header is excluded from calculation
427 current file position relative to the end of the WAV header.
429 virtual off_t
GetPosition() const;
432 /**@name Member variable access */
434 /**Find out the format of the WAV file. Eg 0x01 for PCM, 0x42 or 0x111 for G.723.1.
436 virtual BOOL
SetFormat(unsigned fmt
);
437 virtual BOOL
SetFormat(const PString
& format
);
439 /**Find out the format of the WAV file. Eg 0x01 for PCM, 0x42 or 0x111 for G.723.1.
441 virtual unsigned GetFormat() const;
442 virtual PString
GetFormatAsString() const;
444 /**Find out the number of channels the WAV file has. Typically this is 1 for
445 mono and 2 for stereo.
447 virtual unsigned GetChannels() const;
448 virtual void SetChannels(unsigned v
);
450 /**Find out the sample rate of the WAV file in Hz.
452 virtual unsigned GetSampleRate() const;
453 virtual void SetSampleRate(unsigned v
);
455 /**Find out how may bits there are per sample, eg 8 or 16.
457 virtual unsigned GetSampleSize() const;
458 virtual void SetSampleSize(unsigned v
);
460 /**Find out the size of WAV header presented in the file.
462 off_t
GetHeaderLength() const;
464 /**Find out how many bytes of audio data there are.
466 virtual off_t
GetDataLength();
468 /**Determine if the WAV file is a valid wave file.
471 TRUE indicates that the WAV file is valid
472 FALSE indicates that the WAV file is invalid
474 BOOL
IsValid() const { return isValidWAV
; }
477 *Return a string that describes the WAV format
479 PString
GetFormatString() const
480 { if (formatHandler
== NULL
) return PString("N/A"); else return formatHandler
->GetFormat(); }
483 * enable autoconversion between PCM-16 and the native format
485 void SetAutoconvert();
489 friend class PWAVFileConverter
;
491 BOOL
RawRead(void * buf
, PINDEX len
);
492 BOOL
RawWrite(const void * buf
, PINDEX len
);
494 BOOL
FileRead(void * buf
, PINDEX len
);
495 BOOL
FileWrite(const void * buf
, PINDEX len
);
497 off_t
RawGetPosition() const;
498 BOOL
RawSetPosition(off_t pos
, FilePositionOrigin origin
);
499 off_t
RawGetDataLength();
501 void SetLastReadCount(PINDEX v
) { lastReadCount
= v
; }
503 PWAV::FMTChunk wavFmtChunk
;
504 PBYTEArray extendedHeader
;
508 void SelectFormat(unsigned fmt
);
509 void SelectFormat(const PString
& format
);
511 PBYTEArray wavHeaderData
;
513 BOOL
ProcessHeader();
514 BOOL
GenerateHeader();
519 PWAVFileFormat
* formatHandler
;
522 PWAVFileConverter
* autoConverter
;
527 BOOL header_needs_updating
;
532 # ifndef P_DISABLE_FACTORY_INSTANCES
534 # ifndef P_FACTORY_INSTANCE_PWAVFileConverter
535 # define P_FACTORY_INSTANCE_PWAVFileConverter 1
536 # pragma message("Including PWAVFileConverter factory loader")
537 PLOAD_FACTORY(PWAVFileConverter
, unsigned)
540 # ifndef P_FACTORY_INSTANCE_PWAVFileFormat
541 # define P_FACTORY_INSTANCE_PWAVFileFormat 1
542 # pragma message("Including PWAVFileFormat factory loader")
543 PLOAD_FACTORY(PWAVFileFormat
, unsigned)
553 // End Of File ///////////////////////////////////////////////////////////////