2 Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
34 #include "sound_asset_writer.h"
35 #include "sound_asset.h"
36 #include "exceptions.h"
37 #include "dcp_assert.h"
38 #include "compose.hpp"
39 #include "encryption_context.h"
40 #include <asdcp/AS_DCP.h>
46 struct SoundAssetWriter::ASDCPState
48 ASDCP::PCM::MXFWriter mxf_writer;
49 ASDCP::PCM::FrameBuffer frame_buffer;
50 ASDCP::WriterInfo writer_info;
51 ASDCP::PCM::AudioDescriptor audio_desc;
54 SoundAssetWriter::SoundAssetWriter (SoundAsset* asset, boost::filesystem::path file, Standard standard, ChannelAssignment assign)
55 : AssetWriter (asset, file, standard)
56 , _state (new SoundAssetWriter::ASDCPState)
57 , _sound_asset (asset)
58 , _frame_buffer_offset (0)
60 /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
61 _state->audio_desc.EditRate = ASDCP::Rational (_sound_asset->edit_rate().numerator, _sound_asset->edit_rate().denominator);
62 _state->audio_desc.AudioSamplingRate = ASDCP::Rational (_sound_asset->sampling_rate(), 1);
63 _state->audio_desc.Locked = 0;
64 _state->audio_desc.ChannelCount = _sound_asset->channels ();
65 _state->audio_desc.QuantizationBits = 24;
66 _state->audio_desc.BlockAlign = 3 * _sound_asset->channels();
67 _state->audio_desc.AvgBps = _sound_asset->sampling_rate() * _state->audio_desc.BlockAlign;
68 _state->audio_desc.LinkedTrackID = 0;
69 if (standard == INTEROP) {
70 _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_NONE;
73 case CHANNEL_ASSIGNMENT_51:
74 _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_CFG_1;
76 case CHANNEL_ASSIGNMENT_61:
77 _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_CFG_2;
79 case CHANNEL_ASSIGNMENT_71:
80 _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_CFG_3;
82 case CHANNEL_ASSIGNMENT_WTF:
83 _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_CFG_4;
85 case CHANNEL_ASSIGNMENT_71_DS:
86 _state->audio_desc.ChannelFormat = ASDCP::PCM::CF_CFG_5;
91 _state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
92 _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->audio_desc));
93 memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
95 _sound_asset->fill_writer_info (&_state->writer_info, _sound_asset->id(), standard);
99 SoundAssetWriter::write (float const * const * data, int frames)
101 DCP_ASSERT (!_finalized);
103 static float const clip = 1.0f - (1.0f / pow (2, 23));
106 Kumu::Result_t r = _state->mxf_writer.OpenWrite (_file.string().c_str(), _state->writer_info, _state->audio_desc);
107 if (ASDCP_FAILURE (r)) {
108 boost::throw_exception (FileError ("could not open audio MXF for writing", _file.string(), r));
111 _sound_asset->set_file (_file);
115 int const ch = _sound_asset->channels ();
117 for (int i = 0; i < frames; ++i) {
119 byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
121 /* Write one sample per channel */
122 for (int j = 0; j < ch; ++j) {
123 /* Convert sample to 24-bit int, clipping if necessary. */
124 float x = data[j][i];
127 } else if (x < -clip) {
130 int32_t const s = x * (1 << 23);
132 *out++ = (s & 0xff00) >> 8;
133 *out++ = (s & 0xff0000) >> 16;
135 _frame_buffer_offset += 3 * ch;
137 DCP_ASSERT (_frame_buffer_offset <= int (_state->frame_buffer.Capacity()));
139 /* Finish the MXF frame if required */
140 if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
141 write_current_frame ();
142 _frame_buffer_offset = 0;
143 memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
149 SoundAssetWriter::write_current_frame ()
151 ASDCP::Result_t const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _encryption_context->encryption(), _encryption_context->hmac());
152 if (ASDCP_FAILURE (r)) {
153 boost::throw_exception (MiscError (String::compose ("could not write audio MXF frame (%1)", int (r))));
160 SoundAssetWriter::finalize ()
162 if (_frame_buffer_offset > 0) {
163 write_current_frame ();
166 if (_started && ASDCP_FAILURE (_state->mxf_writer.Finalize())) {
167 boost::throw_exception (MiscError ("could not finalise audio MXF"));
170 _sound_asset->_intrinsic_duration = _frames_written;
171 return AssetWriter::finalize ();