Make sound asset language optional.
[libdcp.git] / src / sound_asset_writer.cc
1 /*
2     Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
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
23     including the two.
24
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.
32 */
33
34
35 /** @file  src/sound_asset_writer.cc
36  *  @brief SoundAssetWriter class
37  */
38
39
40 #include "bitstream.h"
41 #include "sound_asset_writer.h"
42 #include "sound_asset.h"
43 #include "exceptions.h"
44 #include "dcp_assert.h"
45 #include "compose.hpp"
46 #include "crypto_context.h"
47 #include <asdcp/AS_DCP.h>
48 #include <asdcp/Metadata.h>
49 #include <iostream>
50
51
52 using std::min;
53 using std::max;
54 using std::cout;
55 using std::string;
56 using std::vector;
57 using namespace dcp;
58
59
60 struct SoundAssetWriter::ASDCPState
61 {
62         ASDCP::PCM::MXFWriter mxf_writer;
63         ASDCP::PCM::FrameBuffer frame_buffer;
64         ASDCP::WriterInfo writer_info;
65         ASDCP::PCM::AudioDescriptor desc;
66 };
67
68
69 SoundAssetWriter::SoundAssetWriter (SoundAsset* asset, boost::filesystem::path file, bool sync)
70         : AssetWriter (asset, file)
71         , _state (new SoundAssetWriter::ASDCPState)
72         , _asset (asset)
73         , _sync (sync)
74 {
75         DCP_ASSERT (!_sync || _asset->channels() >= 14);
76         DCP_ASSERT (!_sync || _asset->standard() == Standard::SMPTE);
77
78         /* Derived from ASDCP::Wav::SimpleWaveHeader::FillADesc */
79         _state->desc.EditRate = ASDCP::Rational (_asset->edit_rate().numerator, _asset->edit_rate().denominator);
80         _state->desc.AudioSamplingRate = ASDCP::Rational (_asset->sampling_rate(), 1);
81         _state->desc.Locked = 0;
82         _state->desc.ChannelCount = _asset->channels();
83         _state->desc.QuantizationBits = 24;
84         _state->desc.BlockAlign = 3 * _asset->channels();
85         _state->desc.AvgBps = _asset->sampling_rate() * _state->desc.BlockAlign;
86         _state->desc.LinkedTrackID = 0;
87         if (asset->standard() == Standard::INTEROP) {
88                 _state->desc.ChannelFormat = ASDCP::PCM::CF_NONE;
89         } else {
90                 /* As required by Bv2.1 */
91                 _state->desc.ChannelFormat = ASDCP::PCM::CF_CFG_4;
92         }
93
94         /* I'm fairly sure this is not necessary, as ContainerDuration is written
95            in ASDCP's WriteMXFFooter, but it stops a valgrind warning.
96         */
97         _state->desc.ContainerDuration = 0;
98
99         _state->frame_buffer.Capacity (ASDCP::PCM::CalcFrameBufferSize (_state->desc));
100         _state->frame_buffer.Size (ASDCP::PCM::CalcFrameBufferSize (_state->desc));
101         memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
102
103         _asset->fill_writer_info (&_state->writer_info, _asset->id());
104
105         if (_sync) {
106                 _fsk.set_data (create_sync_packets());
107         }
108 }
109
110
111 void
112 SoundAssetWriter::start ()
113 {
114         auto r = _state->mxf_writer.OpenWrite (_file.string().c_str(), _state->writer_info, _state->desc);
115         if (ASDCP_FAILURE(r)) {
116                 boost::throw_exception (FileError("could not open audio MXF for writing", _file.string(), r));
117         }
118
119         if (_asset->standard() == Standard::SMPTE) {
120
121                 ASDCP::MXF::WaveAudioDescriptor* essence_descriptor = nullptr;
122                 _state->mxf_writer.OP1aHeader().GetMDObjectByType(
123                         asdcp_smpte_dict->ul(ASDCP::MDD_WaveAudioDescriptor), reinterpret_cast<ASDCP::MXF::InterchangeObject**>(&essence_descriptor)
124                         );
125                 DCP_ASSERT (essence_descriptor);
126                 essence_descriptor->ChannelAssignment = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioChannelCfg_MCA);
127
128                 auto soundfield = new ASDCP::MXF::SoundfieldGroupLabelSubDescriptor(asdcp_smpte_dict);
129                 GenRandomValue (soundfield->MCALinkID);
130                 if (auto lang = _asset->language()) {
131                         soundfield->RFC5646SpokenLanguage = *lang;
132                 }
133
134                 const MCASoundField field = _asset->channels() > 10 ? MCASoundField::SEVEN_POINT_ONE : MCASoundField::FIVE_POINT_ONE;
135
136                 if (field == MCASoundField::SEVEN_POINT_ONE) {
137                         soundfield->MCATagSymbol = "sg71";
138                         soundfield->MCATagName = "7.1DS";
139                         soundfield->MCALabelDictionaryID = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_71);
140                 } else {
141                         soundfield->MCATagSymbol = "sg51";
142                         soundfield->MCATagName = "5.1";
143                         soundfield->MCALabelDictionaryID = asdcp_smpte_dict->ul(ASDCP::MDD_DCAudioSoundfield_51);
144                 }
145
146                 _state->mxf_writer.OP1aHeader().AddChildObject(soundfield);
147                 essence_descriptor->SubDescriptors.push_back(soundfield->InstanceUID);
148
149                 /* We must describe at least the number of channels in `field', even if they aren't
150                  * in the asset (I think)
151                  */
152                 int descriptors = max(_asset->channels(), field == MCASoundField::FIVE_POINT_ONE ? 6 : 8);
153
154                 auto const used = used_audio_channels();
155
156                 for (auto i = 0; i < descriptors; ++i) {
157                         auto dcp_channel = static_cast<dcp::Channel>(i);
158                         if (find(used.begin(), used.end(), dcp_channel) == used.end()) {
159                                 continue;
160                         }
161                         auto channel = new ASDCP::MXF::AudioChannelLabelSubDescriptor(asdcp_smpte_dict);
162                         GenRandomValue (channel->MCALinkID);
163                         channel->SoundfieldGroupLinkID = soundfield->MCALinkID;
164                         channel->MCAChannelID = i + 1;
165                         channel->MCATagSymbol = "ch" + channel_to_mca_id(dcp_channel, field);
166                         channel->MCATagName = channel_to_mca_name(dcp_channel, field);
167                         if (auto lang = _asset->language()) {
168                                 channel->RFC5646SpokenLanguage = *lang;
169                         }
170                         channel->MCALabelDictionaryID = channel_to_mca_universal_label(dcp_channel, field, asdcp_smpte_dict);
171                         _state->mxf_writer.OP1aHeader().AddChildObject(channel);
172                         essence_descriptor->SubDescriptors.push_back(channel->InstanceUID);
173                 }
174         }
175
176         _asset->set_file (_file);
177         _started = true;
178 }
179
180
181 void
182 SoundAssetWriter::write (float const * const * data, int frames)
183 {
184         DCP_ASSERT (!_finalized);
185         DCP_ASSERT (frames > 0);
186
187         static float const clip = 1.0f - (1.0f / pow (2, 23));
188
189         if (!_started) {
190                 start ();
191         }
192
193         int const ch = _asset->channels ();
194
195         for (int i = 0; i < frames; ++i) {
196
197                 byte_t* out = _state->frame_buffer.Data() + _frame_buffer_offset;
198
199                 /* Write one sample per channel */
200                 for (int j = 0; j < ch; ++j) {
201                         int32_t s = 0;
202                         if (j == 13 && _sync) {
203                                 s = _fsk.get();
204                         } else {
205                                 /* Convert sample to 24-bit int, clipping if necessary. */
206                                 float x = data[j][i];
207                                 if (x > clip) {
208                                         x = clip;
209                                 } else if (x < -clip) {
210                                         x = -clip;
211                                 }
212                                 s = x * (1 << 23);
213                         }
214                         *out++ = (s & 0xff);
215                         *out++ = (s & 0xff00) >> 8;
216                         *out++ = (s & 0xff0000) >> 16;
217                 }
218                 _frame_buffer_offset += 3 * ch;
219
220                 DCP_ASSERT (_frame_buffer_offset <= int(_state->frame_buffer.Capacity()));
221
222                 /* Finish the MXF frame if required */
223                 if (_frame_buffer_offset == int (_state->frame_buffer.Capacity())) {
224                         write_current_frame ();
225                         _frame_buffer_offset = 0;
226                         memset (_state->frame_buffer.Data(), 0, _state->frame_buffer.Capacity());
227                 }
228         }
229 }
230
231 void
232 SoundAssetWriter::write_current_frame ()
233 {
234         auto const r = _state->mxf_writer.WriteFrame (_state->frame_buffer, _crypto_context->context(), _crypto_context->hmac());
235         if (ASDCP_FAILURE(r)) {
236                 boost::throw_exception (MiscError(String::compose("could not write audio MXF frame (%1)", static_cast<int>(r))));
237         }
238
239         ++_frames_written;
240
241         if (_sync) {
242                 /* We need a new set of sync packets for this frame */
243                 _fsk.set_data (create_sync_packets());
244         }
245 }
246
247 bool
248 SoundAssetWriter::finalize ()
249 {
250         if (_frame_buffer_offset > 0) {
251                 write_current_frame ();
252         }
253
254         if (_started) {
255                 auto const r = _state->mxf_writer.Finalize();
256                 if (ASDCP_FAILURE(r)) {
257                         boost::throw_exception (MiscError(String::compose ("could not finalise audio MXF (%1)", static_cast<int>(r))));
258                 }
259         }
260
261         _asset->_intrinsic_duration = _frames_written;
262         return AssetWriter::finalize ();
263 }
264
265
266 /** Calculate and return the sync packets required for this edit unit (aka "frame") */
267 vector<bool>
268 SoundAssetWriter::create_sync_packets ()
269 {
270         /* Parts of this code assumes 48kHz */
271         DCP_ASSERT (_asset->sampling_rate() == 48000);
272
273         /* Encoding of edit rate */
274         int edit_rate_code = 0;
275         /* How many 0 bits are used to pad the end of the packet */
276         int remaining_bits = 0;
277         /* How many packets in this edit unit (i.e. "frame") */
278         int packets = 0;
279         auto const edit_rate = _asset->edit_rate ();
280         if (edit_rate == Fraction(24, 1)) {
281                 edit_rate_code = 0;
282                 remaining_bits = 25;
283                 packets = 4;
284         } else if (edit_rate == Fraction(25, 1)) {
285                 edit_rate_code = 1;
286                 remaining_bits = 20;
287                 packets = 4;
288         } else if (edit_rate == Fraction(30, 1)) {
289                 edit_rate_code = 2;
290                 remaining_bits = 0;
291                 packets = 4;
292         } else if (edit_rate == Fraction(48, 1)) {
293                 edit_rate_code = 3;
294                 remaining_bits = 25;
295                 packets = 2;
296         } else if (edit_rate == Fraction(50, 1)) {
297                 edit_rate_code = 4;
298                 remaining_bits = 20;
299                 packets = 2;
300         } else if (edit_rate == Fraction(60, 1)) {
301                 edit_rate_code = 5;
302                 remaining_bits = 0;
303                 packets = 2;
304         } else if (edit_rate == Fraction(96, 1)) {
305                 edit_rate_code = 6;
306                 remaining_bits = 25;
307                 packets = 1;
308         } else if (edit_rate == Fraction(100, 1)) {
309                 edit_rate_code = 7;
310                 remaining_bits = 20;
311                 packets = 1;
312         } else if (edit_rate == Fraction(120, 1)) {
313                 edit_rate_code = 8;
314                 remaining_bits = 0;
315                 packets = 1;
316         }
317
318         Bitstream bs;
319
320         Kumu::UUID id;
321         DCP_ASSERT (id.DecodeHex(_asset->id().c_str()));
322
323         for (int i = 0; i < packets; ++i) {
324                 bs.write_from_byte (0x4d);
325                 bs.write_from_byte (0x56);
326                 bs.start_crc (0x1021);
327                 bs.write_from_byte (edit_rate_code, 4);
328                 bs.write_from_byte (0, 2);
329                 bs.write_from_byte (_sync_packet, 2);
330                 bs.write_from_byte (id.Value()[i * 4 + 0]);
331                 bs.write_from_byte (id.Value()[i * 4 + 1]);
332                 bs.write_from_byte (id.Value()[i * 4 + 2]);
333                 bs.write_from_byte (id.Value()[i * 4 + 3]);
334                 bs.write_from_word (_frames_written, 24);
335                 bs.write_crc ();
336                 bs.write_from_byte (0, 4);
337                 bs.write_from_word (0, remaining_bits);
338
339                 ++_sync_packet;
340                 if (_sync_packet == 4) {
341                         _sync_packet = 0;
342                 }
343         }
344
345         return bs.get();
346 }
347