2 Copyright (c) 2013-2013, 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_STR(argv);
68 PathList_t TmpFileList;
70 for ( ui32_t i = 0; i < argc; ++i )
71 TmpFileList.push_back(argv[i]);
73 return OpenRead(TmpFileList, PictureRate);
78 ASDCP::AtmosSyncChannelMixer::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
80 Result_t result = RESULT_OK;
81 PathList_t::iterator fi;
82 Kumu::PathList_t file_list;
83 PCM::AudioDescriptor tmpDesc;
85 if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
88 char name_buf[MaxFilePath];
89 result = Dir.Open(argv.front().c_str());
91 if ( KM_SUCCESS(result) )
92 result = Dir.GetNext(name_buf);
94 while ( KM_SUCCESS(result) )
96 if ( name_buf[0] != '.' ) // no hidden files
98 std::string tmp_path = argv.front() + "/" + name_buf;
99 file_list.push_back(tmp_path);
102 result = Dir.GetNext(name_buf);
105 if ( result == RESULT_ENDOFFILE )
116 for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
118 result = OpenRead(*fi, PictureRate);
121 if ( ASDCP_SUCCESS(result) && (m_ChannelCount < ATMOS::SYNC_CHANNEL))
123 // atmos sync channel has not been added
124 result = MixInSilenceChannels();
125 if ( ASDCP_SUCCESS(result) )
126 result = MixInAtmosSyncChannel();
129 if ( ASDCP_SUCCESS(result) )
131 m_ADesc.ChannelCount = m_ChannelCount;
132 m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
144 ASDCP::AtmosSyncChannelMixer::OpenRead(const std::string& file, const Rational& PictureRate)
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);
152 if ( ASDCP_SUCCESS(result))
154 result = I->FillAudioDescriptor(tmpDesc);
157 if ( ASDCP_SUCCESS(result) )
160 if ( m_ChannelCount == 0 )
167 if ( tmpDesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
169 DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
170 return RESULT_FORMAT;
173 if ( tmpDesc.QuantizationBits != m_ADesc.QuantizationBits )
175 DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
176 return RESULT_FORMAT;
179 if ( tmpDesc.ContainerDuration < m_ADesc.ContainerDuration )
180 m_ADesc.ContainerDuration = tmpDesc.ContainerDuration;
182 m_ADesc.BlockAlign += tmpDesc.BlockAlign;
187 if ( ASDCP_SUCCESS(result) )
189 numChannels = tmpDesc.ChannelCount; // default to all channels
190 if ((m_ChannelCount < ATMOS::SYNC_CHANNEL) && (m_ChannelCount + numChannels) > (ATMOS::SYNC_CHANNEL - 1))
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;
199 m_outputs.push_back(std::make_pair(numChannels, I.get()));
200 m_inputs.push_back(I);
202 m_ChannelCount += numChannels;
208 ASDCP::AtmosSyncChannelMixer::MixInSilenceChannels()
210 Result_t result = RESULT_OK;
211 PCM::AudioDescriptor tmpDesc;
212 ui32_t numSilenceChannels = ATMOS::SYNC_CHANNEL - m_ChannelCount - 1;
213 if (numSilenceChannels > 0)
215 mem_ptr<SilenceDataProvider> I = new SilenceDataProvider(numSilenceChannels,
216 m_ADesc.QuantizationBits,
217 m_ADesc.AudioSamplingRate.Numerator,
219 result = I->FillAudioDescriptor(tmpDesc);
220 if ( ASDCP_SUCCESS(result) )
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);
227 assert(m_ChannelCount == (ATMOS::SYNC_CHANNEL - 1));
235 ASDCP::AtmosSyncChannelMixer::MixInAtmosSyncChannel()
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) )
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);
250 assert(m_ChannelCount == ATMOS::SYNC_CHANNEL);
257 ASDCP::AtmosSyncChannelMixer::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
265 ASDCP::AtmosSyncChannelMixer::Reset()
267 Result_t result = RESULT_OK;
268 SourceList::iterator it;
269 SourceList::iterator lastInput = m_inputs.end();
271 for ( it = m_inputs.begin(); it != lastInput && ASDCP_SUCCESS(result) ; ++it )
272 result = (*it)->Reset();
280 ASDCP::AtmosSyncChannelMixer::ReadFrame(PCM::FrameBuffer& OutFB)
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());
290 for ( iter = m_inputs.begin(); iter != lastInput && ASDCP_SUCCESS(result) ; ++iter )
291 result = (*iter)->ReadFrame();
293 if ( ASDCP_SUCCESS(result) )
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();
302 while ( Out_p < End_p && ASDCP_SUCCESS(result) )
304 iter = m_outputs.begin();
305 while ( iter != lastOutput && ASDCP_SUCCESS(result) )
307 result = ((*iter).second)->PutSample((*iter).first, Out_p, &bytesWritten);
308 Out_p += bytesWritten;
313 if ( ASDCP_SUCCESS(result) )
315 assert(Out_p == End_p);
316 OutFB.FrameNumber(m_FramesRead++);
325 // end AtmosSyncChannel_Mixer.cpp