2 Copyright (c) 2013-2014, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
27 /*! \file AtmosSyncChannel_Mixer.cpp
29 \brief Read WAV files(s), multiplex multiple PCM frame buffers including Atmos Sync into one
32 #include <AtmosSyncChannel_Mixer.h>
38 #include <PCMDataProviders.h>
40 using namespace ASDCP;
44 ASDCP::AtmosSyncChannelMixer::AtmosSyncChannelMixer(const byte_t * trackUUID)
45 : m_inputs(), m_outputs(), m_trackUUID(), m_ADesc(), m_ChannelCount(0), m_FramesRead(0)
47 ::memcpy(m_trackUUID, trackUUID, UUIDlen);
50 ASDCP::AtmosSyncChannelMixer::~AtmosSyncChannelMixer()
56 ASDCP::AtmosSyncChannelMixer::clear()
59 std::for_each(m_inputs.begin(), m_inputs.end(), delete_input());
65 ASDCP::AtmosSyncChannelMixer::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate)
67 ASDCP_TEST_NULL(argv);
68 PathList_t TmpFileList;
70 for ( ui32_t i = 0; i < argc; ++i )
72 ASDCP_TEST_NULL_STR(argv[i]);
73 TmpFileList.push_back(argv[i]);
76 return OpenRead(TmpFileList, PictureRate);
81 ASDCP::AtmosSyncChannelMixer::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
83 Result_t result = RESULT_OK;
84 PathList_t::iterator fi;
85 Kumu::PathList_t file_list;
86 PCM::AudioDescriptor tmpDesc;
88 if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
91 char name_buf[MaxFilePath];
92 result = Dir.Open(argv.front().c_str());
94 if ( KM_SUCCESS(result) )
95 result = Dir.GetNext(name_buf);
97 while ( KM_SUCCESS(result) )
99 if ( name_buf[0] != '.' ) // no hidden files
101 std::string tmp_path = argv.front() + "/" + name_buf;
102 file_list.push_back(tmp_path);
105 result = Dir.GetNext(name_buf);
108 if ( result == RESULT_ENDOFFILE )
119 for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
121 result = OpenRead(*fi, PictureRate);
124 if ( ASDCP_SUCCESS(result) && (m_ChannelCount < ATMOS::SYNC_CHANNEL))
126 // atmos sync channel has not been added
127 result = MixInSilenceChannels();
128 if ( ASDCP_SUCCESS(result) )
129 result = MixInAtmosSyncChannel();
132 if ( ASDCP_SUCCESS(result) )
134 m_ADesc.ChannelCount = m_ChannelCount;
135 m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
147 ASDCP::AtmosSyncChannelMixer::OpenRead(const std::string& file, const Rational& PictureRate)
149 Result_t result = RESULT_OK;
150 PCM::AudioDescriptor tmpDesc;
151 ui32_t numChannels = 0;
152 mem_ptr<WAVDataProvider> I = new WAVDataProvider;
153 result = I->OpenRead(file.c_str(), PictureRate);
155 if ( ASDCP_SUCCESS(result))
157 result = I->FillAudioDescriptor(tmpDesc);
160 if ( ASDCP_SUCCESS(result) )
163 if ( m_ChannelCount == 0 )
170 if ( tmpDesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
172 DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
173 return RESULT_FORMAT;
176 if ( tmpDesc.QuantizationBits != m_ADesc.QuantizationBits )
178 DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
179 return RESULT_FORMAT;
182 if ( tmpDesc.ContainerDuration < m_ADesc.ContainerDuration )
183 m_ADesc.ContainerDuration = tmpDesc.ContainerDuration;
185 m_ADesc.BlockAlign += tmpDesc.BlockAlign;
190 if ( ASDCP_SUCCESS(result) )
192 numChannels = tmpDesc.ChannelCount; // default to all channels
193 if ((m_ChannelCount < ATMOS::SYNC_CHANNEL) && (m_ChannelCount + numChannels) > (ATMOS::SYNC_CHANNEL - 1))
195 // need to insert an atmos channel between the channels of this file.
196 numChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
197 m_outputs.push_back(std::make_pair(numChannels, I.get()));
198 m_ChannelCount += numChannels;
199 MixInAtmosSyncChannel();
200 numChannels = tmpDesc.ChannelCount - numChannels;
202 m_outputs.push_back(std::make_pair(numChannels, I.get()));
203 m_inputs.push_back(I);
205 m_ChannelCount += numChannels;
211 ASDCP::AtmosSyncChannelMixer::MixInSilenceChannels()
213 Result_t result = RESULT_OK;
214 PCM::AudioDescriptor tmpDesc;
215 ui32_t numSilenceChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
216 if (numSilenceChannels > 0)
218 mem_ptr<SilenceDataProvider> I = new SilenceDataProvider(numSilenceChannels,
219 m_ADesc.QuantizationBits,
220 m_ADesc.AudioSamplingRate.Numerator,
222 result = I->FillAudioDescriptor(tmpDesc);
223 if ( ASDCP_SUCCESS(result) )
225 m_ADesc.BlockAlign += tmpDesc.BlockAlign;
226 m_ChannelCount += tmpDesc.ChannelCount;
227 m_outputs.push_back(std::make_pair(numSilenceChannels, I.get()));
228 m_inputs.push_back(I);
230 assert(m_ChannelCount == (ATMOS::SYNC_CHANNEL - 1));
238 ASDCP::AtmosSyncChannelMixer::MixInAtmosSyncChannel()
240 Result_t result = RESULT_OK;
241 PCM::AudioDescriptor tmpDesc;
242 mem_ptr<AtmosSyncDataProvider> I = new AtmosSyncDataProvider(m_ADesc.QuantizationBits,
243 m_ADesc.AudioSamplingRate.Numerator,
244 m_ADesc.EditRate, m_trackUUID);
245 result = I->FillAudioDescriptor(tmpDesc);
246 if ( ASDCP_SUCCESS(result) )
248 m_ADesc.BlockAlign += tmpDesc.BlockAlign;
249 m_ChannelCount += tmpDesc.ChannelCount;
250 m_outputs.push_back(std::make_pair(tmpDesc.ChannelCount, I.get()));
251 m_inputs.push_back(I);
253 assert(m_ChannelCount == ATMOS::SYNC_CHANNEL);
260 ASDCP::AtmosSyncChannelMixer::AppendSilenceChannels(const ui32_t& channel_count)
262 if ( m_ADesc.QuantizationBits == 0 )
264 DefaultLogSink().Error("Mixer object contains no channels, call OpenRead() first.\n");
268 Result_t result = RESULT_OK;
269 PCM::AudioDescriptor tmpDesc;
271 if ( channel_count > 0 )
273 Kumu::mem_ptr<SilenceDataProvider> I =
274 new SilenceDataProvider(channel_count,
275 m_ADesc.QuantizationBits,
276 m_ADesc.AudioSamplingRate.Numerator,
279 result = I->FillAudioDescriptor(tmpDesc);
281 if ( ASDCP_SUCCESS(result) )
283 m_ADesc.BlockAlign += tmpDesc.BlockAlign;
284 m_ChannelCount += tmpDesc.ChannelCount;
285 m_ADesc.ChannelCount = m_ChannelCount;
286 m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
288 m_outputs.push_back(std::make_pair(channel_count, I.get()));
289 m_inputs.push_back(I);
299 ASDCP::AtmosSyncChannelMixer::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
307 ASDCP::AtmosSyncChannelMixer::Reset()
309 Result_t result = RESULT_OK;
310 SourceList::iterator it;
311 SourceList::iterator lastInput = m_inputs.end();
313 for ( it = m_inputs.begin(); it != lastInput && ASDCP_SUCCESS(result) ; ++it )
314 result = (*it)->Reset();
322 ASDCP::AtmosSyncChannelMixer::ReadFrame(PCM::FrameBuffer& OutFB)
326 Result_t result = RESULT_OK;
327 SourceList::iterator iter;
328 SourceList::iterator lastInput = m_inputs.end();
329 ui32_t bufSize = PCM::CalcFrameBufferSize(m_ADesc);
330 assert( bufSize <= OutFB.Capacity());
332 for ( iter = m_inputs.begin(); iter != lastInput && ASDCP_SUCCESS(result) ; ++iter )
333 result = (*iter)->ReadFrame();
335 if ( ASDCP_SUCCESS(result) )
338 byte_t* Out_p = OutFB.Data();
339 byte_t* End_p = Out_p + OutFB.Size();
340 ui32_t bytesWritten = 0;
341 OutputList::iterator iter;
342 OutputList::iterator lastOutput = m_outputs.end();
344 while ( Out_p < End_p && ASDCP_SUCCESS(result) )
346 iter = m_outputs.begin();
347 while ( iter != lastOutput && ASDCP_SUCCESS(result) )
349 result = ((*iter).second)->PutSample((*iter).first, Out_p, &bytesWritten);
350 Out_p += bytesWritten;
355 if ( ASDCP_SUCCESS(result) )
357 assert(Out_p == End_p);
358 OutFB.FrameNumber(m_FramesRead++);
367 // end AtmosSyncChannel_Mixer.cpp