X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fsound_asset.cc;h=732bb61029f8282492972b4c6575ab74e31ba83c;hb=0251d3f2986bf70d4721b7127ca6ddcc9da3b256;hp=0b22b4f5cb03c025df804743a8ef34c3e3d5e281;hpb=0e7591e3bf95d4abe08d854850b6fc4e411586b0;p=libdcp.git diff --git a/src/sound_asset.cc b/src/sound_asset.cc index 0b22b4f5..732bb610 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -17,25 +17,80 @@ */ +/** @file src/sound_asset.cc + * @brief An asset made up of WAV files + */ + #include #include #include +#include +#include "KM_fileio.h" #include "AS_DCP.h" #include "sound_asset.h" #include "util.h" +#include "exceptions.h" +#include "sound_frame.h" using namespace std; using namespace boost; using namespace libdcp; -SoundAsset::SoundAsset (list const & files, string p, int fps, int len) - : Asset (p, fps, len) +SoundAsset::SoundAsset ( + vector const & files, string directory, string mxf_name, sigc::signal1* progress, int fps, int length + ) + : MXFAsset (directory, mxf_name, progress, fps, 0, length) + , _channels (files.size ()) + , _sampling_rate (0) +{ + construct (sigc::bind (sigc::mem_fun (*this, &SoundAsset::path_from_channel), files)); +} + +SoundAsset::SoundAsset ( + sigc::slot get_path, string directory, string mxf_name, sigc::signal1* progress, int fps, int length, int channels + ) + : MXFAsset (directory, mxf_name, progress, fps, 0, length) + , _channels (channels) + , _sampling_rate (0) +{ + construct (get_path); +} + +SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int entry_point, int length) + : MXFAsset (directory, mxf_name, 0, fps, entry_point, length) + , _channels (0) +{ + ASDCP::PCM::MXFReader reader; + if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) { + throw FileError ("could not open MXF file for reading", path().string()); + } + + + ASDCP::PCM::AudioDescriptor desc; + if (ASDCP_FAILURE (reader.FillAudioDescriptor (desc))) { + throw DCPReadError ("could not read audio MXF information"); + } + + _sampling_rate = desc.AudioSamplingRate.Numerator / desc.AudioSamplingRate.Denominator; + _channels = desc.ChannelCount; +} + +string +SoundAsset::path_from_channel (Channel channel, vector const & files) +{ + unsigned int const c = int (channel); + assert (c < files.size ()); + return files[c]; +} + +void +SoundAsset::construct (sigc::slot get_path) { ASDCP::Rational asdcp_fps (_fps, 1); - ASDCP::PCM::WAVParser pcm_parser_channel[files.size()]; - if (pcm_parser_channel[0].OpenRead (files.front().c_str(), asdcp_fps)) { - throw runtime_error ("could not open WAV file for reading"); + ASDCP::PCM::WAVParser pcm_parser_channel[_channels]; + if (pcm_parser_channel[0].OpenRead (get_path(LEFT).c_str(), asdcp_fps)) { + throw FileError ("could not open WAV file for reading", get_path(LEFT)); } ASDCP::PCM::AudioDescriptor audio_desc; @@ -43,24 +98,33 @@ SoundAsset::SoundAsset (list const & files, string p, int fps, int len) audio_desc.ChannelCount = 0; audio_desc.BlockAlign = 0; audio_desc.EditRate = asdcp_fps; - audio_desc.AvgBps = audio_desc.AvgBps * files.size (); + audio_desc.AvgBps = audio_desc.AvgBps * _channels; - ASDCP::PCM::FrameBuffer frame_buffer_channel[files.size()]; - ASDCP::PCM::AudioDescriptor audio_desc_channel[files.size()]; - - int j = 0; - for (list::const_iterator i = files.begin(); i != files.end(); ++i) { + Channel channels[] = { + LEFT, + RIGHT, + CENTRE, + LFE, + LS, + RS + }; + + ASDCP::PCM::FrameBuffer frame_buffer_channel[_channels]; + ASDCP::PCM::AudioDescriptor audio_desc_channel[_channels]; + + for (int i = 0; i < _channels; ++i) { + + string const path = get_path (channels[i]); - if (ASDCP_FAILURE (pcm_parser_channel[j].OpenRead (i->c_str(), asdcp_fps))) { - throw runtime_error ("could not open WAV file for reading"); + if (ASDCP_FAILURE (pcm_parser_channel[i].OpenRead (path.c_str(), asdcp_fps))) { + throw FileError ("could not open WAV file for reading", path); } - pcm_parser_channel[j].FillAudioDescriptor (audio_desc_channel[j]); - frame_buffer_channel[j].Capacity (ASDCP::PCM::CalcFrameBufferSize (audio_desc_channel[j])); + pcm_parser_channel[i].FillAudioDescriptor (audio_desc_channel[i]); + frame_buffer_channel[i].Capacity (ASDCP::PCM::CalcFrameBufferSize (audio_desc_channel[i])); - audio_desc.ChannelCount += audio_desc_channel[j].ChannelCount; - audio_desc.BlockAlign += audio_desc_channel[j].BlockAlign; - ++j; + audio_desc.ChannelCount += audio_desc_channel[i].ChannelCount; + audio_desc.BlockAlign += audio_desc_channel[i].BlockAlign; } ASDCP::PCM::FrameBuffer frame_buffer; @@ -71,8 +135,8 @@ SoundAsset::SoundAsset (list const & files, string p, int fps, int len) fill_writer_info (&writer_info); ASDCP::PCM::MXFWriter mxf_writer; - if (ASDCP_FAILURE (mxf_writer.OpenWrite (_mxf_path.c_str(), writer_info, audio_desc))) { - throw runtime_error ("could not open audio MXF for writing"); + if (ASDCP_FAILURE (mxf_writer.OpenWrite (path().string().c_str(), writer_info, audio_desc))) { + throw FileError ("could not open audio MXF for writing", path().string()); } for (int i = 0; i < _length; ++i) { @@ -82,19 +146,19 @@ SoundAsset::SoundAsset (list const & files, string p, int fps, int len) byte_t sample_size = ASDCP::PCM::CalcSampleSize (audio_desc_channel[0]); int offset = 0; - for (list::size_type j = 0; j < files.size(); ++j) { + for (int j = 0; j < _channels; ++j) { memset (frame_buffer_channel[j].Data(), 0, frame_buffer_channel[j].Capacity()); if (ASDCP_FAILURE (pcm_parser_channel[j].ReadFrame (frame_buffer_channel[j]))) { - throw runtime_error ("could not read audio frame"); + throw MiscError ("could not read audio frame"); } if (frame_buffer_channel[j].Size() != frame_buffer_channel[j].Capacity()) { - throw runtime_error ("short audio frame"); + throw MiscError ("short audio frame"); } } while (data_s < data_e) { - for (list::size_type j = 0; j < files.size(); ++j) { + for (int j = 0; j < _channels; ++j) { byte_t* frame = frame_buffer_channel[j].Data() + offset; memcpy (data_s, frame, sample_size); data_s += sample_size; @@ -103,17 +167,17 @@ SoundAsset::SoundAsset (list const & files, string p, int fps, int len) } if (ASDCP_FAILURE (mxf_writer.WriteFrame (frame_buffer, 0, 0))) { - throw runtime_error ("could not write audio MXF frame"); + throw MiscError ("could not write audio MXF frame"); } - Progress (float (i) / _length); + if (_progress) { + (*_progress) (0.5 * float (i) / _length); + } } if (ASDCP_FAILURE (mxf_writer.Finalize())) { - throw runtime_error ("could not finalise audio MXF"); + throw MiscError ("could not finalise audio MXF"); } - - _digest = make_digest (_mxf_path); } void @@ -121,7 +185,7 @@ SoundAsset::write_to_cpl (ostream& s) const { s << " \n" << " urn:uuid:" << _uuid << "\n" - << " " << filesystem::path(_mxf_path).filename() << "\n" + << " " << _file_name << "\n" << " " << _fps << " 1\n" << " " << _length << "\n" << " 0\n" @@ -129,3 +193,78 @@ SoundAsset::write_to_cpl (ostream& s) const << " \n"; } +list +SoundAsset::equals (shared_ptr other, EqualityOptions opt) const +{ + list notes = MXFAsset::equals (other, opt); + + if (opt.flags & MXF_INSPECT) { + ASDCP::PCM::MXFReader reader_A; + if (ASDCP_FAILURE (reader_A.OpenRead (path().string().c_str()))) { + cout << "failed " << path() << "\n"; + throw FileError ("could not open MXF file for reading", path().string()); + } + + ASDCP::PCM::MXFReader reader_B; + if (ASDCP_FAILURE (reader_B.OpenRead (other->path().string().c_str()))) { + cout << "failed " << other->path() << "\n"; + throw FileError ("could not open MXF file for reading", path().string()); + } + + ASDCP::PCM::AudioDescriptor desc_A; + if (ASDCP_FAILURE (reader_A.FillAudioDescriptor (desc_A))) { + throw DCPReadError ("could not read audio MXF information"); + } + ASDCP::PCM::AudioDescriptor desc_B; + if (ASDCP_FAILURE (reader_B.FillAudioDescriptor (desc_B))) { + throw DCPReadError ("could not read audio MXF information"); + } + + if ( + desc_A.EditRate != desc_B.EditRate || + desc_A.AudioSamplingRate != desc_B.AudioSamplingRate || + desc_A.Locked != desc_B.Locked || + desc_A.ChannelCount != desc_B.ChannelCount || + desc_A.QuantizationBits != desc_B.QuantizationBits || + desc_A.BlockAlign != desc_B.BlockAlign || + desc_A.AvgBps != desc_B.AvgBps || + desc_A.LinkedTrackID != desc_B.LinkedTrackID || + desc_A.ContainerDuration != desc_B.ContainerDuration +// desc_A.ChannelFormat != desc_B.ChannelFormat || + ) { + + notes.push_back ("audio MXF picture descriptors differ"); + } + + ASDCP::PCM::FrameBuffer buffer_A (1 * Kumu::Megabyte); + ASDCP::PCM::FrameBuffer buffer_B (1 * Kumu::Megabyte); + + for (int i = 0; i < _length; ++i) { + if (ASDCP_FAILURE (reader_A.ReadFrame (0, buffer_A))) { + throw DCPReadError ("could not read audio frame"); + } + + if (ASDCP_FAILURE (reader_B.ReadFrame (0, buffer_B))) { + throw DCPReadError ("could not read audio frame"); + } + + if (buffer_A.Size() != buffer_B.Size()) { + notes.push_back ("sizes of audio data for frame " + lexical_cast(i) + " differ"); + continue; + } + + if (memcmp (buffer_A.RoData(), buffer_B.RoData(), buffer_A.Size()) != 0) { + notes.push_back ("PCM data for frame " + lexical_cast(i) + " differ"); + continue; + } + } + } + + return notes; +} + +shared_ptr +SoundAsset::get_frame (int n) const +{ + return shared_ptr (new SoundFrame (path().string(), n + _entry_point)); +}