mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-11-03 21:40:52 -05:00 
			
		
		
		
	The BWFFile class correctly indicates errors like file access issues and problems reading or writing headers using the BWFFile::error() and BWFFile::errorString() operations. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6751 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
		
			
				
	
	
		
			211 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef BWF_FILE_HPP__
 | 
						|
#define BWF_FILE_HPP__
 | 
						|
 | 
						|
#include <array>
 | 
						|
 | 
						|
#include <QFile>
 | 
						|
#include <QMap>
 | 
						|
#include <QByteArray>
 | 
						|
 | 
						|
#include "pimpl_h.hpp"
 | 
						|
 | 
						|
class QObject;
 | 
						|
class QString;
 | 
						|
class QAudioFormat;
 | 
						|
 | 
						|
//
 | 
						|
// BWFFile - Broadcast Wave Format File (a.k.a. WAV file)
 | 
						|
//
 | 
						|
// The  BWF file  format is  a  backward compatible  variation of  the
 | 
						|
// Microsoft  WAV file  format. It  contains  an extra  chunk with  id
 | 
						|
// 'bext' that contains metadata defined by the EBU in:
 | 
						|
//
 | 
						|
//  https://tech.ebu.ch/docs/tech/tech3285.pdf
 | 
						|
//
 | 
						|
// Also relevant is the recommendation document:
 | 
						|
//
 | 
						|
//  https://tech.ebu.ch/docs/r/r098.pdf
 | 
						|
//
 | 
						|
// which suggests a format to the free text coding history field.
 | 
						|
//
 | 
						|
// This class also supports the LIST-INFO chunk type which also allows
 | 
						|
// metadata to be  added to a WAV  file, the defined INFO  tag ids are
 | 
						|
// documented here:
 | 
						|
//
 | 
						|
//  http://bwfmetaedit.sourceforge.net/listinfo.html
 | 
						|
//
 | 
						|
// These  ids  are not  enforced  but  they  are recommended  as  most
 | 
						|
// operating systems and audio applications  recognize some or more of
 | 
						|
// them. Notably Microsoft Windows is not one of the operating systems
 | 
						|
// that  does :(  In fact  there seems  to be  no documented  metadata
 | 
						|
// tagging format that Windows Explorer recognizes.
 | 
						|
//
 | 
						|
// Changes to  the 'bext' fields  and the LIST-INFO dictionary  may be
 | 
						|
// made right up  until the file is closed as  the relevant chunks are
 | 
						|
// saved to the end of the file after the end of the sample data.
 | 
						|
//
 | 
						|
// This class emulates the QFile class, in fact it uses a QFile object
 | 
						|
// instance internally and forwards many of its operations directly to
 | 
						|
// it.
 | 
						|
//
 | 
						|
// BWFFile  is a  QIODevice subclass  and the  implementation provides
 | 
						|
// access to  the audio sample  data contained in  the BWF file  as if
 | 
						|
// only that data were  in the file. I.e. the first  sample is at file
 | 
						|
// offset zero  and the  size of the  file is the  size of  the sample
 | 
						|
// data.  The headers,  trailers and  metadata are  hidden but  can be
 | 
						|
// accessed by the operations below.
 | 
						|
//
 | 
						|
class BWFFile
 | 
						|
  : public QIODevice
 | 
						|
{
 | 
						|
  Q_OBJECT
 | 
						|
public:
 | 
						|
  using FileHandleFlags = QFile::FileHandleFlags;
 | 
						|
  using Permissions = QFile::Permissions;
 | 
						|
  using FileError = QFile::FileError;
 | 
						|
  using MemoryMapFlags = QFile::MemoryMapFlags;
 | 
						|
  using InfoDictionary = QMap<std::array<char, 4>, QByteArray>;
 | 
						|
  using UMID = std::array<quint8, 64>;
 | 
						|
 | 
						|
  explicit BWFFile (QAudioFormat const&, QObject * parent = nullptr);
 | 
						|
  explicit BWFFile (QAudioFormat const&, QString const& name,
 | 
						|
                    QObject * parent = nullptr);
 | 
						|
 | 
						|
  // The  InfoDictionary should  contain  valid  WAV format  LIST-INFO
 | 
						|
  // identifiers as keys, a list of them can be found here:
 | 
						|
  //
 | 
						|
  // http://bwfmetaedit.sourceforge.net/listinfo.html
 | 
						|
  //
 | 
						|
  // For  files  opened for  ReadOnly  access  the dictionary  is  not
 | 
						|
  // written to  the file.  For  files opened ReadWrite,  any existing
 | 
						|
  // LIST-INFO tags will  be merged into the dictionary  when the file
 | 
						|
  // is opened and if the file  is modified the merged dictionary will
 | 
						|
  // be written back to the file.
 | 
						|
  //
 | 
						|
  // Note that the sample  data may no be in the  native endian, it is
 | 
						|
  // the   callers   responsibility   to  do   any   required   endian
 | 
						|
  // conversions. The  internal data is  always in native  endian with
 | 
						|
  // conversions  being handled  automatically. Use  the BWF::format()
 | 
						|
  // operation     to    access     the    format     including    the
 | 
						|
  // QAudioFormat::byteOrder()  operation to  determine the  data byte
 | 
						|
  // ordering.
 | 
						|
  //
 | 
						|
  explicit BWFFile (QAudioFormat const&, QString const& name,
 | 
						|
                    InfoDictionary const&, QObject * parent = nullptr);
 | 
						|
 | 
						|
  ~BWFFile ();
 | 
						|
  QAudioFormat const& format () const;
 | 
						|
  InfoDictionary& list_info ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Broadcast Audio Extension fields
 | 
						|
  //
 | 
						|
  // If any of these modifiers are  called then a "bext" chunk will be
 | 
						|
  // written to the file if the  file is writeable and the sample data
 | 
						|
  // is modified.
 | 
						|
  //
 | 
						|
  enum class BextVersion : quint16 {v_0, v_1, v_2};
 | 
						|
  BextVersion bext_version () const;
 | 
						|
  void bext_version (BextVersion = BextVersion::v_2);
 | 
						|
 | 
						|
  QByteArray bext_description () const;
 | 
						|
  void bext_description (QByteArray const&); // max 256 bytes
 | 
						|
 | 
						|
  QByteArray bext_originator () const;
 | 
						|
  void bext_originator (QByteArray const&);        // max 32 bytes
 | 
						|
 | 
						|
  QByteArray bext_originator_reference () const;
 | 
						|
  void bext_originator_reference (QByteArray const&); // max 32 bytes
 | 
						|
 | 
						|
  QDateTime bext_origination_date_time () const;
 | 
						|
  void bext_origination_date_time (QDateTime const&); // 1s resolution
 | 
						|
 | 
						|
  quint64 bext_time_reference () const;
 | 
						|
  void bext_time_reference (quint64); // samples since midnight at start
 | 
						|
 | 
						|
  UMID bext_umid () const; // bext version >= 1 only
 | 
						|
  void bext_umid (UMID const&);
 | 
						|
 | 
						|
  quint16 bext_loudness_value () const;
 | 
						|
  void bext_loudness_value (quint16); // bext version >= 2 only
 | 
						|
 | 
						|
  quint16 bext_loudness_range () const;
 | 
						|
  void bext_loudness_range (quint16); // bext version >= 2 only
 | 
						|
 | 
						|
  quint16 bext_max_true_peak_level () const;
 | 
						|
  void bext_max_true_peak_level (quint16); // bext version >= 2 only
 | 
						|
 | 
						|
  quint16 bext_max_momentary_loudness () const;
 | 
						|
  void bext_max_momentary_loudness (quint16); // bext version >= 2 only
 | 
						|
 | 
						|
  quint16 bext_max_short_term_loudness () const;
 | 
						|
  void bext_max_short_term_loudness (quint16); // bext version >= 2 only
 | 
						|
 | 
						|
  QByteArray bext_coding_history () const;
 | 
						|
  void bext_coding_history (QByteArray const&); // See EBU R 98
 | 
						|
 | 
						|
 | 
						|
  // Emulate QFile interface
 | 
						|
  bool open (OpenMode) override;
 | 
						|
  bool open (FILE *, OpenMode, FileHandleFlags = QFile::DontCloseHandle);
 | 
						|
  bool open (int fd, OpenMode, FileHandleFlags = QFile::DontCloseHandle);
 | 
						|
  bool copy (QString const& new_name);
 | 
						|
  bool exists () const;
 | 
						|
  bool link (QString const& link_name);
 | 
						|
  bool remove ();
 | 
						|
  bool rename (QString const& new_name);
 | 
						|
  void setFileName (QString const& name);
 | 
						|
  QString symLinkTarget () const;
 | 
						|
  QString fileName () const;
 | 
						|
  Permissions permissions () const;
 | 
						|
 | 
						|
  // Resize is of the sample data portion, header and trailer chunks
 | 
						|
  // are excess to the given size
 | 
						|
  bool resize (qint64 new_size);
 | 
						|
 | 
						|
  bool setPermissions (Permissions permissions);
 | 
						|
  FileError error () const;
 | 
						|
  bool flush ();
 | 
						|
  int handle () const;
 | 
						|
 | 
						|
  // The mapping offset is relative to the start of the sample data
 | 
						|
  uchar * map (qint64 offset, qint64 size,
 | 
						|
               MemoryMapFlags = QFile::NoOptions);
 | 
						|
  bool unmap (uchar * address);
 | 
						|
 | 
						|
  void unsetError ();
 | 
						|
 | 
						|
 | 
						|
  //
 | 
						|
  // QIODevice implementation
 | 
						|
  //
 | 
						|
 | 
						|
  // The size returned is of the sample data only, header and trailer
 | 
						|
  // chunks are hidden and handled internally
 | 
						|
  qint64 size () const override;
 | 
						|
 | 
						|
  bool isSequential () const override;
 | 
						|
 | 
						|
  // The reset  operation clears the  'bext' and LIST-INFO as  if they
 | 
						|
  // were  never supplied.  If the  file  is writable  the 'bext'  and
 | 
						|
  // LIST-INFO chunks will not be  written making the resulting file a
 | 
						|
  // lowest common denominator WAV file.
 | 
						|
  bool reset () override;
 | 
						|
 | 
						|
  // Seek offsets are relative to the start of the sample data
 | 
						|
  bool seek (qint64) override;
 | 
						|
 | 
						|
  // this can fail due to updating header issues, errors are ignored
 | 
						|
  void close () override;
 | 
						|
 | 
						|
protected:
 | 
						|
  qint64 readData (char * data, qint64 max_size) override;
 | 
						|
  qint64 writeData (char const* data, qint64 max_size) override;
 | 
						|
 | 
						|
private:
 | 
						|
  class impl;
 | 
						|
  pimpl<impl> m_;
 | 
						|
};
 | 
						|
 | 
						|
#endif
 |