class Exception : public boost::exception { public: std::string title() const; std::string message() const; long code() const; std::string function() const; std::string file() const; int line() const; std::string what() const; };#define ML_ASSERT(exp) ((exp)? ((void)0): ml::AssertionFailed("Ошибка времени выполнения", #exp, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__))#define ML_THROW(msg) throw ml::Exception() \ << ml::__title__("Ошибка времени выполнения") \ << ml::__message__(msg) \ << ml::__function__(BOOST_CURRENT_FUNCTION) \ << ml::__file__(__FILE__) \ << ml::__line__(__LINE__)
class Reader : public boost::noncopyable { private: bifstream m_fileStream; ///< Файловый поток std::vector<Point> m_points; ///< Буфер прочитанных значений std::string m_caption; ///< Название unsigned int m_channels; ///< Число каналов unsigned int m_frequency; ///< Частота private: void readHeader(); void readPoints(); public: Reader(const boost::filesystem::path& filename); std::string caption() const; unsigned int channels() const; unsigned int frequency() const; size_t size() const; std::vector<Point> read(size_t base, size_t num); std::vector<double> read(size_t base, size_t num, unsigned int channel); Point operator[](size_t index) const; };
std::vector<Point> Reader::read(size_t base, size_t num){using namespace std;vector<Point> result; if (base >= 0 && base < m_points.size() && (base + num) <= m_points.size()) { result.reserve( num ); copy(m_points.begin() + base, m_points.begin() + base + num, back_inserter(result)); } else { boost::format msg("illegal read interval: \"[%1%; %2%]\""); msg % base % (base + num); ML_THROW(msg.str()); }return result;}std::vector<double> Reader::read(size_t base, size_t num, unsigned int channel){using namespace std;using namespace boost::phoenix;vector<double> result; if (channel >= channels() ) { boost::format msg("channel value \"%1%\" is not correct. Channels number: \"[%2%\""); msg % channel % channels(); ML_THROW(msg.str()); } if (base < 0 || base >= m_points.size() || (base + num) > m_points.size()) { boost::format msg("illegal read interval: \"[%1%; %2%]\""); msg % base % (base + num); ML_THROW(msg.str()); } result.reserve(num); transform(m_points.begin() + base, m_points.begin() + base + num, back_inserter(result), boost::phoenix::bind<double>(&Point::operator[], _1, channel));return result;}Point Reader::operator[](size_t index) const{ if (index > m_points.size() - 1) { boost::format msg("index value \"%1%\" out of range: \"[%2%; %3%]\""); msg % index % 0 % (m_points.size() - 1); ML_THROW(msg.str()); } return m_points[index];}
class PlayerWD : public InternalWD{ friend class AbstractWD; osc::ReadStream m_stream; ///< Поток для чтения boost::shared_ptr<ml::thread> m_thread; ///< Внутренний поток double m_frequency; ///< Частота следования измеренных значений из файла Buffer m_buffer; ///< Буфер последних значений bool fIsEof; ///< Флаг конца файла bool fIsFailed; ///< Флаг ошибкиprivate: void routine();private: PlayerWD(const std::string& filename);public: ~PlayerWD(); AbstractWD::Sample Weight();};
PlayerWD::PlayerWD(const std::string& filename) : m_buffer(SAMPLE_BUFFER_SIZE), m_frequency(0), fIsEof(false), fIsFailed(false){using namespace boost;using namespace boost::filesystem;path p(filename); shared_ptr<osc::Reader> reader(new osc::Reader( p )); m_stream.setReader(reader); m_frequency = reader->frequency(); if (m_frequency == 0) ML_TITLE_THROW(MSG__PLAYERWD_ERROR, "Invalid file"); // Запускаем цикл выборки значений из файла m_thread.reset( new ml::thread(boost::bind(&PlayerWD::routine, this)) ); m_thread->start();}void PlayerWD::routine(){ try { Sample s; m_stream >> s; m_buffer.put( s ); } catch(osc::eof&) { fIsEof = true; // Помещаем в буфер пустой сэмпл // Нужно чтобы выпустить клиентский поток, // читающий в данный момент из буфера, если буфер пуст m_buffer.put( Sample() ); m_thread->stop(); } catch (ml::Exception& e) { // Проблема копирования считанного значения в селектор fIsFailed = true; Log::out() << e.what() << endl; // Помещаем в буфер пустой сэмпл // Нужно чтобы выпустить клиентский поток, // читающий в данный момент из буфера, если буфер пуст m_buffer.put( Sample() ); m_thread->stop(); } // Выдавать измерения нужно с заданной частотой sleep_us( int(1000 / m_frequency) );}