2016-02-19 18:38:42 +03:00
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
2016-04-24 14:16:03 +03:00
|
|
|
#define __STDC_FORMAT_MACROS
|
2016-04-07 15:34:42 +03:00
|
|
|
#include <inttypes.h>
|
|
|
|
#include <limits>
|
2016-02-19 18:38:42 +03:00
|
|
|
#include "MLFDataDeserializer.h"
|
|
|
|
#include "ConfigHelper.h"
|
2016-09-08 16:36:34 +03:00
|
|
|
#include "SequenceData.h"
|
2016-02-19 18:38:42 +03:00
|
|
|
#include "../HTKMLFReader/htkfeatio.h"
|
|
|
|
#include "../HTKMLFReader/msra_mgram.h"
|
|
|
|
#include "latticearchive.h"
|
2016-10-04 14:43:35 +03:00
|
|
|
#include "StringUtil.h"
|
2016-02-19 18:38:42 +03:00
|
|
|
|
2016-09-08 16:36:34 +03:00
|
|
|
|
2016-04-07 15:34:42 +03:00
|
|
|
#undef max // max is defined in minwindef.h
|
|
|
|
|
2016-02-19 18:38:42 +03:00
|
|
|
namespace Microsoft { namespace MSR { namespace CNTK {
|
|
|
|
|
2016-04-15 16:06:46 +03:00
|
|
|
using namespace std;
|
|
|
|
|
2016-02-19 18:38:42 +03:00
|
|
|
static float s_oneFloat = 1.0;
|
|
|
|
static double s_oneDouble = 1.0;
|
|
|
|
|
|
|
|
// Currently we only have a single mlf chunk that contains a vector of all labels.
|
2016-04-28 17:59:17 +03:00
|
|
|
// TODO: In the future MLF should be converted to a more compact format that is amenable to chunking.
|
2016-02-19 18:38:42 +03:00
|
|
|
class MLFDataDeserializer::MLFChunk : public Chunk
|
|
|
|
{
|
|
|
|
MLFDataDeserializer* m_parent;
|
|
|
|
public:
|
|
|
|
MLFChunk(MLFDataDeserializer* parent) : m_parent(parent)
|
|
|
|
{}
|
|
|
|
|
2016-04-15 16:06:46 +03:00
|
|
|
virtual void GetSequence(size_t sequenceId, vector<SequenceDataPtr>& result) override
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-03-04 16:06:08 +03:00
|
|
|
m_parent->GetSequenceById(sequenceId, result);
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Inner class for an utterance.
|
|
|
|
struct MLFUtterance : SequenceDescription
|
|
|
|
{
|
|
|
|
size_t m_sequenceStart;
|
|
|
|
};
|
|
|
|
|
2016-04-15 13:36:08 +03:00
|
|
|
MLFDataDeserializer::MLFDataDeserializer(CorpusDescriptorPtr corpus, const ConfigParameters& cfg, bool primary)
|
2016-04-01 18:15:44 +03:00
|
|
|
{
|
2016-04-28 17:59:17 +03:00
|
|
|
// TODO: This should be read in one place, potentially given by SGD.
|
|
|
|
m_frameMode = (ConfigValue)cfg("frameMode", "true");
|
2016-04-01 18:15:44 +03:00
|
|
|
|
2016-04-28 17:59:17 +03:00
|
|
|
// MLF cannot control chunking.
|
2016-04-15 13:36:08 +03:00
|
|
|
if (primary)
|
|
|
|
{
|
2016-04-28 17:59:17 +03:00
|
|
|
LogicError("Mlf deserializer does not support primary mode - it cannot control chunking.");
|
2016-04-15 13:36:08 +03:00
|
|
|
}
|
|
|
|
|
2016-05-12 15:53:39 +03:00
|
|
|
argvector<ConfigValue> inputs = cfg("input");
|
2016-04-01 18:15:44 +03:00
|
|
|
if (inputs.size() != 1)
|
|
|
|
{
|
2016-04-28 17:59:17 +03:00
|
|
|
LogicError("MLFDataDeserializer supports a single input stream only.");
|
2016-04-01 18:15:44 +03:00
|
|
|
}
|
|
|
|
|
2016-10-04 17:43:24 +03:00
|
|
|
std::wstring precision = cfg(L"precision", L"float");;
|
2016-10-04 14:43:35 +03:00
|
|
|
m_elementType = AreEqualIgnoreCase(precision, L"float") ? ElementType::tfloat : ElementType::tdouble;
|
|
|
|
|
2016-04-01 18:15:44 +03:00
|
|
|
ConfigParameters input = inputs.front();
|
|
|
|
auto inputName = input.GetMemberIds().front();
|
|
|
|
|
|
|
|
ConfigParameters streamConfig = input(inputName);
|
|
|
|
ConfigHelper config(streamConfig);
|
|
|
|
|
|
|
|
size_t dimension = config.GetLabelDimension();
|
|
|
|
|
2016-04-15 16:06:46 +03:00
|
|
|
wstring labelMappingFile = streamConfig(L"labelMappingFile", L"");
|
|
|
|
InitializeChunkDescriptions(corpus, config, labelMappingFile, dimension);
|
|
|
|
InitializeStream(inputName, dimension);
|
2016-04-01 18:15:44 +03:00
|
|
|
}
|
|
|
|
|
2016-04-15 16:06:46 +03:00
|
|
|
MLFDataDeserializer::MLFDataDeserializer(CorpusDescriptorPtr corpus, const ConfigParameters& labelConfig, const wstring& name)
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-03-16 19:21:38 +03:00
|
|
|
// The frame mode is currently specified once per configuration,
|
|
|
|
// not in the configuration of a particular deserializer, but on a higher level in the configuration.
|
|
|
|
// Because of that we are using find method below.
|
|
|
|
m_frameMode = labelConfig.Find("frameMode", "true");
|
2016-02-19 18:38:42 +03:00
|
|
|
|
|
|
|
ConfigHelper config(labelConfig);
|
|
|
|
|
|
|
|
config.CheckLabelType();
|
|
|
|
size_t dimension = config.GetLabelDimension();
|
|
|
|
|
2016-04-07 15:34:42 +03:00
|
|
|
if (dimension > numeric_limits<IndexType>::max())
|
|
|
|
{
|
|
|
|
RuntimeError("Label dimension (%" PRIu64 ") exceeds the maximum allowed "
|
|
|
|
"value (%" PRIu64 ")\n", dimension, (size_t)numeric_limits<IndexType>::max());
|
|
|
|
}
|
|
|
|
|
2016-10-04 17:43:24 +03:00
|
|
|
std::wstring precision = labelConfig(L"precision", L"float");;
|
2016-10-04 14:43:35 +03:00
|
|
|
m_elementType = AreEqualIgnoreCase(precision, L"float") ? ElementType::tfloat : ElementType::tdouble;
|
|
|
|
|
2016-04-15 16:06:46 +03:00
|
|
|
wstring labelMappingFile = labelConfig(L"labelMappingFile", L"");
|
|
|
|
InitializeChunkDescriptions(corpus, config, labelMappingFile, dimension);
|
|
|
|
InitializeStream(name, dimension);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Currently we create a single chunk only.
|
|
|
|
void MLFDataDeserializer::InitializeChunkDescriptions(CorpusDescriptorPtr corpus, const ConfigHelper& config, const wstring& stateListPath, size_t dimension)
|
|
|
|
{
|
2016-02-19 18:38:42 +03:00
|
|
|
// TODO: Similarly to the old reader, currently we assume all Mlfs will have same root name (key)
|
|
|
|
// restrict MLF reader to these files--will make stuff much faster without having to use shortened input files
|
|
|
|
|
|
|
|
// TODO: currently we do not use symbol and word tables.
|
|
|
|
const msra::lm::CSymbolSet* wordTable = nullptr;
|
2016-04-15 16:06:46 +03:00
|
|
|
unordered_map<const char*, int>* symbolTable = nullptr;
|
|
|
|
vector<wstring> mlfPaths = config.GetMlfPaths();
|
2016-02-19 18:38:42 +03:00
|
|
|
|
|
|
|
// TODO: Currently we still use the old IO module. This will be refactored later.
|
|
|
|
const double htkTimeToFrame = 100000.0; // default is 10ms
|
2016-04-15 16:06:46 +03:00
|
|
|
msra::asr::htkmlfreader<msra::asr::htkmlfentry, msra::lattices::lattice::htkmlfwordsequence> labels(mlfPaths, set<wstring>(), stateListPath, wordTable, symbolTable, htkTimeToFrame);
|
2016-02-19 18:38:42 +03:00
|
|
|
|
|
|
|
// Make sure 'msra::asr::htkmlfreader' type has a move constructor
|
|
|
|
static_assert(
|
2016-04-15 16:06:46 +03:00
|
|
|
is_move_constructible<
|
|
|
|
msra::asr::htkmlfreader<msra::asr::htkmlfentry,
|
|
|
|
msra::lattices::lattice::htkmlfwordsequence >> ::value,
|
2016-02-19 18:38:42 +03:00
|
|
|
"Type 'msra::asr::htkmlfreader' should be move constructible!");
|
|
|
|
|
|
|
|
MLFUtterance description;
|
2016-05-24 15:27:31 +03:00
|
|
|
size_t numClasses = 0;
|
2016-02-19 18:38:42 +03:00
|
|
|
size_t totalFrames = 0;
|
|
|
|
|
2016-05-17 14:07:25 +03:00
|
|
|
const auto& stringRegistry = corpus->GetStringRegistry();
|
2016-05-09 18:27:55 +03:00
|
|
|
|
|
|
|
// TODO resize m_keyToSequence with number of IDs from string registry
|
|
|
|
|
2016-02-19 18:38:42 +03:00
|
|
|
for (const auto& l : labels)
|
|
|
|
{
|
2016-03-14 13:10:44 +03:00
|
|
|
// Currently the string registry contains only utterances described in scp.
|
|
|
|
// So here we skip all others.
|
2016-04-04 15:42:31 +03:00
|
|
|
size_t id = 0;
|
2016-05-24 20:09:02 +03:00
|
|
|
if (!stringRegistry.TryGet(msra::strfun::utf8(l.first), id))
|
2016-03-03 19:04:28 +03:00
|
|
|
continue;
|
|
|
|
|
2016-04-26 16:09:10 +03:00
|
|
|
description.m_key.m_sequence = id;
|
2016-03-03 19:04:28 +03:00
|
|
|
|
2016-02-19 18:38:42 +03:00
|
|
|
const auto& utterance = l.second;
|
|
|
|
description.m_sequenceStart = m_classIds.size();
|
2016-05-27 18:02:21 +03:00
|
|
|
uint32_t numberOfFrames = 0;
|
2016-02-19 18:38:42 +03:00
|
|
|
|
|
|
|
foreach_index(i, utterance)
|
|
|
|
{
|
|
|
|
const auto& timespan = utterance[i];
|
|
|
|
if ((i == 0 && timespan.firstframe != 0) ||
|
|
|
|
(i > 0 && utterance[i - 1].firstframe + utterance[i - 1].numframes != timespan.firstframe))
|
|
|
|
{
|
2016-05-27 18:20:09 +03:00
|
|
|
RuntimeError("Labels are not in the consecutive order MLF in label set: %ls", l.first.c_str());
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (timespan.classid >= dimension)
|
|
|
|
{
|
2016-04-15 16:06:46 +03:00
|
|
|
RuntimeError("Class id %d exceeds the model output dimension %d.", (int)timespan.classid, (int)dimension);
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (timespan.classid != static_cast<msra::dbn::CLASSIDTYPE>(timespan.classid))
|
|
|
|
{
|
|
|
|
RuntimeError("CLASSIDTYPE has too few bits");
|
|
|
|
}
|
|
|
|
|
2016-05-27 18:02:21 +03:00
|
|
|
if (SEQUENCELEN_MAX < timespan.firstframe + timespan.numframes)
|
2016-05-24 20:35:00 +03:00
|
|
|
{
|
|
|
|
RuntimeError("Maximum number of sample per sequence exceeded.");
|
|
|
|
}
|
|
|
|
|
2016-05-24 15:27:31 +03:00
|
|
|
numClasses = max(numClasses, (size_t)(1u + timespan.classid));
|
|
|
|
|
2016-02-19 18:38:42 +03:00
|
|
|
for (size_t t = timespan.firstframe; t < timespan.firstframe + timespan.numframes; t++)
|
|
|
|
{
|
|
|
|
m_classIds.push_back(timespan.classid);
|
|
|
|
numberOfFrames++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
description.m_numberOfSamples = numberOfFrames;
|
2016-05-09 18:27:55 +03:00
|
|
|
m_utteranceIndex.push_back(totalFrames);
|
2016-02-19 18:38:42 +03:00
|
|
|
totalFrames += numberOfFrames;
|
|
|
|
|
2016-05-09 18:27:55 +03:00
|
|
|
if (m_keyToSequence.size() <= description.m_key.m_sequence)
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-05-09 18:27:55 +03:00
|
|
|
m_keyToSequence.resize(description.m_key.m_sequence + 1, SIZE_MAX);
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
2016-05-09 18:27:55 +03:00
|
|
|
assert(m_keyToSequence[description.m_key.m_sequence] == SIZE_MAX);
|
|
|
|
m_keyToSequence[description.m_key.m_sequence] = m_utteranceIndex.size() - 1;
|
|
|
|
m_numberOfSequences++;
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
2016-05-09 18:27:55 +03:00
|
|
|
m_utteranceIndex.push_back(totalFrames);
|
2016-02-19 18:38:42 +03:00
|
|
|
|
2016-03-03 14:58:06 +03:00
|
|
|
m_totalNumberOfFrames = totalFrames;
|
|
|
|
|
2016-05-24 15:27:31 +03:00
|
|
|
fprintf(stderr, "MLFDataDeserializer::MLFDataDeserializer: %" PRIu64 " utterances with %" PRIu64 " frames in %" PRIu64 " classes\n",
|
|
|
|
m_numberOfSequences,
|
|
|
|
m_totalNumberOfFrames,
|
|
|
|
numClasses);
|
2016-02-19 18:38:42 +03:00
|
|
|
|
2016-03-14 13:10:44 +03:00
|
|
|
// Initializing array of labels.
|
2016-03-04 16:34:51 +03:00
|
|
|
m_categories.reserve(dimension);
|
2016-04-07 15:34:42 +03:00
|
|
|
m_categoryIndices.reserve(dimension);
|
2016-03-04 16:34:51 +03:00
|
|
|
for (size_t i = 0; i < dimension; ++i)
|
|
|
|
{
|
2016-09-08 16:36:34 +03:00
|
|
|
auto category = make_shared<CategorySequenceData>();
|
2016-04-07 15:34:42 +03:00
|
|
|
m_categoryIndices.push_back(static_cast<IndexType>(i));
|
|
|
|
category->m_indices = &(m_categoryIndices[i]);
|
|
|
|
category->m_nnzCounts.resize(1);
|
|
|
|
category->m_nnzCounts[0] = 1;
|
|
|
|
category->m_totalNnzCount = 1;
|
|
|
|
category->m_numberOfSamples = 1;
|
2016-03-04 16:34:51 +03:00
|
|
|
if (m_elementType == ElementType::tfloat)
|
|
|
|
{
|
|
|
|
category->m_data = &s_oneFloat;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(m_elementType == ElementType::tdouble);
|
|
|
|
category->m_data = &s_oneDouble;
|
|
|
|
}
|
|
|
|
m_categories.push_back(category);
|
|
|
|
}
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
2016-04-15 16:06:46 +03:00
|
|
|
void MLFDataDeserializer::InitializeStream(const wstring& name, size_t dimension)
|
|
|
|
{
|
|
|
|
// Initializing stream description - a single stream of MLF data.
|
|
|
|
StreamDescriptionPtr stream = make_shared<StreamDescription>();
|
|
|
|
stream->m_id = 0;
|
|
|
|
stream->m_name = name;
|
|
|
|
stream->m_sampleLayout = make_shared<TensorShape>(dimension);
|
|
|
|
stream->m_storageType = StorageType::sparse_csc;
|
|
|
|
stream->m_elementType = m_elementType;
|
|
|
|
m_streams.push_back(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitializeFeatureInformation();
|
|
|
|
void InitializeAugmentationWindow(ConfigHelper& config);
|
|
|
|
|
2016-03-14 13:10:44 +03:00
|
|
|
// Currently MLF has a single chunk.
|
|
|
|
// TODO: This will be changed when the deserializer properly supports chunking.
|
2016-03-01 13:11:49 +03:00
|
|
|
ChunkDescriptions MLFDataDeserializer::GetChunkDescriptions()
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-04-15 16:06:46 +03:00
|
|
|
auto cd = make_shared<ChunkDescription>();
|
2016-03-21 12:50:00 +03:00
|
|
|
cd->m_id = 0;
|
2016-05-09 18:27:55 +03:00
|
|
|
cd->m_numberOfSequences = m_frameMode ? m_totalNumberOfFrames : m_numberOfSequences;
|
|
|
|
cd->m_numberOfSamples = m_totalNumberOfFrames;
|
2016-03-01 13:11:49 +03:00
|
|
|
return ChunkDescriptions{cd};
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
2016-03-14 13:10:44 +03:00
|
|
|
// Gets sequences for a particular chunk.
|
2016-05-24 20:35:00 +03:00
|
|
|
void MLFDataDeserializer::GetSequencesForChunk(ChunkIdType, vector<SequenceDescription>& result)
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-05-09 18:27:55 +03:00
|
|
|
UNUSED(result);
|
|
|
|
LogicError("Mlf deserializer does not support primary mode - it cannot control chunking.");
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
2016-05-24 20:35:00 +03:00
|
|
|
ChunkPtr MLFDataDeserializer::GetChunk(ChunkIdType chunkId)
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
|
|
|
UNUSED(chunkId);
|
|
|
|
assert(chunkId == 0);
|
2016-03-30 18:05:20 +03:00
|
|
|
return make_shared<MLFChunk>(this);
|
|
|
|
};
|
2016-02-19 18:38:42 +03:00
|
|
|
|
2016-03-16 19:21:38 +03:00
|
|
|
// Sparse labels for an utterance.
|
|
|
|
template <class ElemType>
|
|
|
|
struct MLFSequenceData : SparseSequenceData
|
|
|
|
{
|
2016-04-15 16:06:46 +03:00
|
|
|
vector<ElemType> m_values;
|
|
|
|
unique_ptr<IndexType[]> m_indicesPtr;
|
2016-03-16 19:21:38 +03:00
|
|
|
|
2016-05-09 18:27:55 +03:00
|
|
|
MLFSequenceData(size_t numberOfSamples) :
|
2016-04-07 15:34:42 +03:00
|
|
|
m_values(numberOfSamples, 1),
|
|
|
|
m_indicesPtr(new IndexType[numberOfSamples])
|
2016-03-16 19:21:38 +03:00
|
|
|
{
|
2016-04-07 15:34:42 +03:00
|
|
|
if (numberOfSamples > numeric_limits<IndexType>::max())
|
|
|
|
{
|
|
|
|
RuntimeError("Number of samples in an MLFSequence (%" PRIu64 ") "
|
2016-05-09 18:27:55 +03:00
|
|
|
"exceeds the maximum allowed value (%" PRIu64 ")\n",
|
2016-04-07 15:34:42 +03:00
|
|
|
numberOfSamples, (size_t)numeric_limits<IndexType>::max());
|
|
|
|
}
|
|
|
|
|
|
|
|
m_nnzCounts.resize(numberOfSamples, static_cast<IndexType>(1));
|
2016-05-27 18:02:21 +03:00
|
|
|
m_numberOfSamples = (uint32_t) numberOfSamples;
|
2016-04-07 15:34:42 +03:00
|
|
|
m_totalNnzCount = static_cast<IndexType>(numberOfSamples);
|
|
|
|
m_indices = m_indicesPtr.get();
|
2016-09-08 16:36:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
const void* GetDataBuffer() override
|
|
|
|
{
|
|
|
|
return m_values.data();
|
2016-03-16 19:21:38 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-04-15 16:06:46 +03:00
|
|
|
void MLFDataDeserializer::GetSequenceById(size_t sequenceId, vector<SequenceDataPtr>& result)
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-03-16 19:21:38 +03:00
|
|
|
if (m_frameMode)
|
|
|
|
{
|
2016-05-09 18:27:55 +03:00
|
|
|
size_t label = m_classIds[sequenceId];
|
2016-03-16 19:21:38 +03:00
|
|
|
assert(label < m_categories.size());
|
|
|
|
result.push_back(m_categories[label]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Packing labels for the utterance into sparse sequence.
|
2016-04-07 15:34:42 +03:00
|
|
|
size_t startFrameIndex = m_utteranceIndex[sequenceId];
|
|
|
|
size_t numberOfSamples = m_utteranceIndex[sequenceId + 1] - startFrameIndex;
|
2016-03-16 19:21:38 +03:00
|
|
|
SparseSequenceDataPtr s;
|
|
|
|
if (m_elementType == ElementType::tfloat)
|
|
|
|
{
|
2016-04-15 16:06:46 +03:00
|
|
|
s = make_shared<MLFSequenceData<float>>(numberOfSamples);
|
2016-03-16 19:21:38 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(m_elementType == ElementType::tdouble);
|
2016-04-15 16:06:46 +03:00
|
|
|
s = make_shared<MLFSequenceData<double>>(numberOfSamples);
|
2016-03-16 19:21:38 +03:00
|
|
|
}
|
|
|
|
|
2016-04-07 15:34:42 +03:00
|
|
|
for (size_t i = 0; i < numberOfSamples; i++)
|
2016-03-16 19:21:38 +03:00
|
|
|
{
|
2016-04-07 15:34:42 +03:00
|
|
|
size_t frameIndex = startFrameIndex + i;
|
2016-05-09 18:27:55 +03:00
|
|
|
size_t label = m_classIds[frameIndex];
|
2016-04-07 15:34:42 +03:00
|
|
|
s->m_indices[i] = static_cast<IndexType>(label);
|
2016-03-16 19:21:38 +03:00
|
|
|
}
|
|
|
|
result.push_back(s);
|
|
|
|
}
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
2016-05-24 20:35:00 +03:00
|
|
|
bool MLFDataDeserializer::GetSequenceDescriptionByKey(const KeyType& key, SequenceDescription& result)
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-05-09 18:27:55 +03:00
|
|
|
|
|
|
|
auto sequenceId = key.m_sequence < m_keyToSequence.size() ? m_keyToSequence[key.m_sequence] : SIZE_MAX;
|
|
|
|
|
|
|
|
if (sequenceId == SIZE_MAX)
|
2016-02-19 18:38:42 +03:00
|
|
|
{
|
2016-05-24 20:35:00 +03:00
|
|
|
return false;
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
2016-05-09 18:27:55 +03:00
|
|
|
result.m_chunkId = 0;
|
|
|
|
result.m_key = key;
|
|
|
|
|
2016-03-16 19:21:38 +03:00
|
|
|
if (m_frameMode)
|
|
|
|
{
|
2016-05-09 18:27:55 +03:00
|
|
|
size_t index = m_utteranceIndex[sequenceId] + key.m_sample;
|
|
|
|
result.m_id = index;
|
|
|
|
result.m_numberOfSamples = 1;
|
2016-03-16 19:21:38 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-05-09 18:27:55 +03:00
|
|
|
assert(result.m_key.m_sample == 0);
|
|
|
|
result.m_id = sequenceId;
|
2016-05-27 18:02:21 +03:00
|
|
|
result.m_numberOfSamples = (uint32_t) (m_utteranceIndex[sequenceId + 1] - m_utteranceIndex[sequenceId]);
|
2016-03-16 19:21:38 +03:00
|
|
|
}
|
2016-05-24 20:35:00 +03:00
|
|
|
return true;
|
2016-02-19 18:38:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}}}
|