Initial Commit
This commit is contained in:
@@ -0,0 +1,210 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user