mixed synopsis
[asdcplib.git] / src / AtmosSyncChannel_Mixer.cpp
1 /*
2 Copyright (c) 2013-2013, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*! \file    AtmosSyncChannel_Mixer.cpp
28     \version $Id$
29     \brief   Read WAV files(s), multiplex multiple PCM frame buffers including Atmos Sync into one
30 */
31
32 #include <AtmosSyncChannel_Mixer.h>
33
34 #include <algorithm>
35
36 #include <AS_DCP.h>
37 #include <KM_log.h>
38 #include <PCMDataProviders.h>
39
40 using namespace ASDCP;
41 using namespace Kumu;
42
43 //
44 ASDCP::AtmosSyncChannelMixer::AtmosSyncChannelMixer(const byte_t * trackUUID)
45     : m_inputs(), m_outputs(), m_trackUUID(), m_ADesc(), m_ChannelCount(0), m_FramesRead(0)
46 {
47   ::memcpy(m_trackUUID, trackUUID, UUIDlen);
48 }
49
50 ASDCP::AtmosSyncChannelMixer::~AtmosSyncChannelMixer()
51 {
52   clear();
53 }
54
55 void
56 ASDCP::AtmosSyncChannelMixer::clear()
57 {
58   m_outputs.clear();
59   std::for_each(m_inputs.begin(), m_inputs.end(), delete_input());
60   m_inputs.clear();
61 }
62
63 //
64 Result_t
65 ASDCP::AtmosSyncChannelMixer::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate)
66 {
67   ASDCP_TEST_NULL_STR(argv);
68   PathList_t TmpFileList;
69
70   for ( ui32_t i = 0; i < argc; ++i )
71     TmpFileList.push_back(argv[i]);
72
73   return OpenRead(TmpFileList, PictureRate);
74 }
75
76 //
77 Result_t
78 ASDCP::AtmosSyncChannelMixer::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
79 {
80   Result_t result = RESULT_OK;
81   PathList_t::iterator fi;
82   Kumu::PathList_t file_list;
83   PCM::AudioDescriptor tmpDesc;
84
85   if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
86   {
87     DirScanner Dir;
88     char name_buf[MaxFilePath];
89     result = Dir.Open(argv.front().c_str());
90
91     if ( KM_SUCCESS(result) )
92       result = Dir.GetNext(name_buf);
93
94     while ( KM_SUCCESS(result) )
95         {
96           if ( name_buf[0] != '.' ) // no hidden files
97       {
98         std::string tmp_path = argv.front() + "/" + name_buf;
99         file_list.push_back(tmp_path);
100       }
101
102           result = Dir.GetNext(name_buf);
103         }
104
105     if ( result == RESULT_ENDOFFILE )
106         {
107           result = RESULT_OK;
108           file_list.sort();
109         }
110   }
111   else
112   {
113     file_list = argv;
114   }
115
116   for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
117   {
118     result = OpenRead(*fi, PictureRate);
119   }
120
121   if ( ASDCP_SUCCESS(result) && (m_ChannelCount < ATMOS::SYNC_CHANNEL))
122   {
123     // atmos sync channel has not been added
124     result = MixInSilenceChannels();
125     if ( ASDCP_SUCCESS(result) )
126       result = MixInAtmosSyncChannel();
127   }
128
129   if ( ASDCP_SUCCESS(result) )
130   {
131     m_ADesc.ChannelCount = m_ChannelCount;
132     m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
133   }
134   else
135   {
136     clear();
137   }
138
139   return result;
140 }
141
142 //
143 Result_t
144 ASDCP::AtmosSyncChannelMixer::OpenRead(const std::string& file, const Rational& PictureRate)
145 {
146   Result_t result = RESULT_OK;
147   PCM::AudioDescriptor tmpDesc;
148   ui32_t numChannels = 0;
149   mem_ptr<WAVDataProvider> I = new WAVDataProvider;
150   result = I->OpenRead(file.c_str(), PictureRate);
151
152   if ( ASDCP_SUCCESS(result))
153   {
154     result = I->FillAudioDescriptor(tmpDesc);
155   }
156
157   if ( ASDCP_SUCCESS(result) )
158   {
159
160     if ( m_ChannelCount == 0 )
161     {
162       m_ADesc = tmpDesc;
163     }
164     else
165     {
166
167       if ( tmpDesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
168       {
169         DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
170         return RESULT_FORMAT;
171       }
172
173       if ( tmpDesc.QuantizationBits  != m_ADesc.QuantizationBits )
174       {
175         DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
176         return RESULT_FORMAT;
177       }
178
179       if ( tmpDesc.ContainerDuration < m_ADesc.ContainerDuration )
180         m_ADesc.ContainerDuration = tmpDesc.ContainerDuration;
181
182       m_ADesc.BlockAlign += tmpDesc.BlockAlign;
183     }
184   }
185
186
187   if ( ASDCP_SUCCESS(result) )
188   {
189     numChannels = tmpDesc.ChannelCount; // default to all channels
190     if ((m_ChannelCount < ATMOS::SYNC_CHANNEL) && (m_ChannelCount + numChannels) > (ATMOS::SYNC_CHANNEL - 1))
191     {
192       // need to insert an atmos channel between the channels of this file.
193       numChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
194       m_outputs.push_back(std::make_pair(numChannels, I.get()));
195       m_ChannelCount += numChannels;
196       MixInAtmosSyncChannel();
197       numChannels = tmpDesc.ChannelCount - numChannels;
198     }
199     m_outputs.push_back(std::make_pair(numChannels, I.get()));
200     m_inputs.push_back(I);
201     I.release();
202     m_ChannelCount += numChannels;
203   }
204   return result;
205 }
206
207 Result_t
208 ASDCP::AtmosSyncChannelMixer::MixInSilenceChannels()
209 {
210   Result_t result = RESULT_OK;
211   PCM::AudioDescriptor tmpDesc;
212   ui32_t numSilenceChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
213   if (numSilenceChannels > 0)
214   {
215     mem_ptr<SilenceDataProvider> I = new SilenceDataProvider(numSilenceChannels,
216                                                              m_ADesc.QuantizationBits,
217                                                              m_ADesc.AudioSamplingRate.Numerator,
218                                                              m_ADesc.EditRate);
219     result = I->FillAudioDescriptor(tmpDesc);
220     if ( ASDCP_SUCCESS(result) )
221     {
222       m_ADesc.BlockAlign += tmpDesc.BlockAlign;
223       m_ChannelCount += tmpDesc.ChannelCount;
224       m_outputs.push_back(std::make_pair(numSilenceChannels, I.get()));
225       m_inputs.push_back(I);
226       I.release();
227       assert(m_ChannelCount == (ATMOS::SYNC_CHANNEL - 1));
228     }
229   }
230   return result;
231 }
232
233 //
234 Result_t
235 ASDCP::AtmosSyncChannelMixer::MixInAtmosSyncChannel()
236 {
237   Result_t result = RESULT_OK;
238   PCM::AudioDescriptor tmpDesc;
239   mem_ptr<AtmosSyncDataProvider> I = new AtmosSyncDataProvider(m_ADesc.QuantizationBits,
240                                                                m_ADesc.AudioSamplingRate.Numerator,
241                                                                m_ADesc.EditRate, m_trackUUID);
242   result = I->FillAudioDescriptor(tmpDesc);
243   if ( ASDCP_SUCCESS(result) )
244   {
245     m_ADesc.BlockAlign += tmpDesc.BlockAlign;
246     m_ChannelCount += tmpDesc.ChannelCount;
247     m_outputs.push_back(std::make_pair(tmpDesc.ChannelCount, I.get()));
248     m_inputs.push_back(I);
249     I.release();
250     assert(m_ChannelCount == ATMOS::SYNC_CHANNEL);
251   }
252   return result;
253 }
254
255 //
256 Result_t
257 ASDCP::AtmosSyncChannelMixer::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
258 {
259   ADesc = m_ADesc;
260   return RESULT_OK;
261 }
262
263 //
264 Result_t
265 ASDCP::AtmosSyncChannelMixer::Reset()
266 {
267   Result_t result = RESULT_OK;
268   SourceList::iterator it;
269   SourceList::iterator lastInput = m_inputs.end();
270
271   for ( it = m_inputs.begin(); it != lastInput && ASDCP_SUCCESS(result) ; ++it )
272     result = (*it)->Reset();
273
274   return result;
275 }
276
277
278 //2
279 Result_t
280 ASDCP::AtmosSyncChannelMixer::ReadFrame(PCM::FrameBuffer& OutFB)
281 {
282
283
284   Result_t result = RESULT_OK;
285   SourceList::iterator iter;
286   SourceList::iterator lastInput = m_inputs.end();
287   ui32_t bufSize = PCM::CalcFrameBufferSize(m_ADesc);
288   assert( bufSize <= OutFB.Capacity());
289
290   for ( iter = m_inputs.begin(); iter != lastInput && ASDCP_SUCCESS(result) ; ++iter )
291     result = (*iter)->ReadFrame();
292
293   if ( ASDCP_SUCCESS(result) )
294   {
295     OutFB.Size(bufSize);
296     byte_t* Out_p = OutFB.Data();
297     byte_t* End_p = Out_p + OutFB.Size();
298     ui32_t bytesWritten = 0;
299     OutputList::iterator iter;
300     OutputList::iterator lastOutput = m_outputs.end();
301
302     while ( Out_p < End_p && ASDCP_SUCCESS(result) )
303         {
304         iter = m_outputs.begin();
305         while ( iter != lastOutput && ASDCP_SUCCESS(result) )
306         {
307             result = ((*iter).second)->PutSample((*iter).first, Out_p, &bytesWritten);
308             Out_p += bytesWritten;
309             ++iter;
310         }
311     }
312
313     if ( ASDCP_SUCCESS(result) )
314     {
315       assert(Out_p == End_p);
316       OutFB.FrameNumber(m_FramesRead++);
317     }
318   }
319
320   return result;
321 }
322
323
324 //
325 // end AtmosSyncChannel_Mixer.cpp
326 //