<commit_before>/*
 * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

# include  "architec.h"
# include  "entity.h"
# include  "expression.h"
# include  "sequential.h"
# include  <typeinfo>
# include  <cassert>

int Architecture::elaborate(Entity*entity)
{
      int errors = 0;

	// Constant assignments in the architecture get their types
	// from the constant declaration itself. Elaborate the value
	// expression with the declared type.

      for (map<perm_string,struct const_t*>::iterator cur = use_constants_.begin()
		 ; cur != use_constants_.end() ; ++cur) {
	    cur->second->val->elaborate_expr(entity, this, cur->second->typ);
      }
      for (map<perm_string,struct const_t*>::iterator cur = cur_constants_.begin()
		 ; cur != cur_constants_.end() ; ++cur) {
	    cur->second->val->elaborate_expr(entity, this, cur->second->typ);
      }

        // Elaborate initializer expressions for signals & variables
      for (map<perm_string,Signal*>::iterator cur = old_signals_.begin()
		 ; cur != old_signals_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }
      for (map<perm_string,Signal*>::iterator cur = new_signals_.begin()
		 ; cur != new_signals_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }
      for (map<perm_string,Variable*>::iterator cur = old_variables_.begin()
		 ; cur != old_variables_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }
      for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
		 ; cur != new_variables_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }

      for (list<Architecture::Statement*>::iterator cur = statements_.begin()
		 ; cur != statements_.end() ; ++cur) {

	    int cur_errors = (*cur)->elaborate(entity, this);
	    errors += cur_errors;
      }

      if (errors > 0) {
	    cerr << errors << " errors in "
		 << name_ << " architecture of "
		 << entity->get_name() << "." << endl;
      }

      return errors;
}

int Architecture::Statement::elaborate(Entity*, Architecture*)
{
      return 0;
}

int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;

      ComponentBase*base = arc->find_component(cname_);
      if (base == 0) {
	    cerr << get_fileline() << ": error: No component declaration"
		 << " for instance " << iname_
		 << " of " << cname_ << "." << endl;
	    return 1;
      }

      for (map<perm_string,Expression*>::const_iterator cur = generic_map_.begin()
		 ; cur != generic_map_.end() ; ++cur) {
	      // check if generic from component instantiation
	      // exists in the component declaration
	    const InterfacePort*iparm = base->find_generic(cur->first);
	    if (iparm == 0) {
		  cerr << get_fileline() << ": warning: No generic " << cur->first
		       << " in component " << cname_ << "." << endl;
		  continue;
	    }

	    ExpName* tmp;
	    if (cur->second && (tmp = dynamic_cast<ExpName*>(cur->second)))
		  errors += tmp->elaborate_rval(ent, arc, iparm);

	    if (cur->second)
		  errors += cur->second->elaborate_expr(ent, arc, iparm->type);
      }

      for (map<perm_string,Expression*>::const_iterator cur = port_map_.begin()
		 ; cur != port_map_.end() ; ++cur) {
	      // check if a port from component instantiation
	      // exists in the component declaration
	    const InterfacePort*iport = base->find_port(cur->first);
	    if (iport == 0) {
		  cerr << get_fileline() << ": error: No port " << cur->first
		       << " in component " << cname_ << "." << endl;
		  errors += 1;
		  continue;
	    }

	    ExpName* tmp;
	    if (cur->second && (tmp = dynamic_cast<ExpName*>(cur->second)))
		  errors += tmp->elaborate_rval(ent, arc, iport);
	      /* It is possible for the port to be explicitly
		 unconnected. In that case, the Expression will be nil */

	    if (cur->second)
		  cur->second->elaborate_expr(ent, arc, iport->type);
      }

      return errors;
}

int GenerateStatement::elaborate_statements(Entity*ent, Architecture*arc)
{
      int errors = 0;
      for (list<Architecture::Statement*>::iterator cur = statements_.begin()
		 ; cur != statements_.end() ; ++cur) {
	    Architecture::Statement*curp = *cur;
	    errors += curp->elaborate(ent, arc);
      }
      return errors;
}

int ForGenerate::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;
      arc->push_genvar_type(genvar_, lsb_->probe_type(ent, arc));
      errors += elaborate_statements(ent, arc);
      arc->pop_genvar_type();
      return errors;
}

int IfGenerate::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;
      errors += elaborate_statements(ent, arc);
      return errors;
}

/*
 * This method attempts to rewrite the process content as an
 * always-@(n-edge <expr>) version of the same statement. This makes
 * for a more natural translation to Verilog, if it comes to that.
 */
int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
{
	// If there are multiple sensitivity expressions, I give up.
      if (sensitivity_list_.size() != 1)
	    return -1;

	// If there are multiple statements, I give up.
      if (statements_list_.size() != 1)
	    return -1;

      Expression*se = sensitivity_list_.front();
      SequentialStmt*stmt_raw = statements_list_.front();

	// If the statement is not an if-statement, I give up.
      IfSequential*stmt = dynamic_cast<IfSequential*> (stmt_raw);
      if (stmt == 0)
	    return -1;

	// If the "if" statement has a false clause, then give up.
      if (stmt->false_size() != 0)
	    return -1;

      const Expression*ce_raw = stmt->peek_condition();
	// Now we have matched this pattern:
	//   process(<expr>) begin if <ce_raw>...
	// The <ce_raw> is the condition.

      if (const ExpFunc*ce_func = dynamic_cast<const ExpFunc*>(ce_raw)) {
	    if (ce_func->func_args() != 1)
		  return -1;
	    if (ce_func->func_name()!="rising_edge" && ce_func->func_name()!="falling_edge")
		  return -1;

	    if (! se->symbolic_compare(ce_func->func_arg(0)))
		return -1;

	      // We've matched this pattern:
	      //  process(<se>) if (rising_edge(<se>)) then ...
	      // and we can convert it to:
	      //  always @(posedge <se>) ...

	    ExpEdge::fun_t use_edge;
	    if (ce_func->func_name()=="rising_edge")
		  use_edge = ExpEdge::POSEDGE;
	    else if (ce_func->func_name()=="falling_edge")
		  use_edge = ExpEdge::NEGEDGE;
	    else
		  use_edge = ExpEdge::ANYEDGE;

	      // Replace the sensitivity expression with an edge
	      // expression. The ExpEdge expression signals that this
	      // is an always-@(edge) statement.
	    ExpEdge*edge = new ExpEdge(use_edge, se);
	    assert(sensitivity_list_.size() == 1);
	    sensitivity_list_.pop_front();
	    sensitivity_list_.push_front(edge);

	      // Replace the statement with the body of the always
	      // statement, which is the true clause of the top "if"
	      // statement. There should be no "else" clause.
	    assert(statements_list_.size() == 1);
	    statements_list_.pop_front();
	    stmt->extract_true(statements_list_);

	    delete stmt;
	    return 0;
      }

	// Here we expect the condition to be
	//    <name>'event AND <name>='1'.
	// So if ce_raw is not a logical AND, I give up.
      const ExpLogical*ce = dynamic_cast<const ExpLogical*> (ce_raw);
      if (ce == 0)
	    return -1;
      if (ce->logic_fun() != ExpLogical::AND)
	    return -1;

      const Expression*op1_raw = ce->peek_operand1();
      const Expression*op2_raw = ce->peek_operand2();
      if (dynamic_cast<const ExpAttribute*>(op2_raw)) {
	    const Expression*tmp = op1_raw;
	    op1_raw = op2_raw;
	    op2_raw = tmp;
      }

	// If operand1 is not an 'event attribute, I give up.
      const ExpAttribute*op1 = dynamic_cast<const ExpAttribute*>(op1_raw);
      if (op1 == 0)
	    return -1;
      if (op1->peek_attribute() != "event")
	    return -1;

      const ExpRelation*op2 = dynamic_cast<const ExpRelation*>(op2_raw);
      if (op2 == 0)
	    return -1;
      if (op2->relation_fun() != ExpRelation::EQ)
	    return -1;

      const Expression*op2a_raw = op2->peek_operand1();
      const Expression*op2b_raw = op2->peek_operand2();

      if (dynamic_cast<const ExpCharacter*>(op2a_raw)) {
	    const Expression*tmp = op2b_raw;
	    op2b_raw = op2a_raw;
	    op2a_raw = tmp;
      }

      if (! se->symbolic_compare(op1->peek_base()))
	    return -1;

      const ExpCharacter*op2b = dynamic_cast<const ExpCharacter*>(op2b_raw);
      if (op2b->value() != '1' && op2b->value() != '0')
	    return -1;

	// We've matched this pattern:
	//   process (<se>) if (<se>'event and <se> = <op2b>) then ...
	// And we can convert it to:
	//   always @(<N>edge <se>) ...

	// Replace the sensitivity expression with an edge
	// expression. The ExpEdge expression signals that this is an
	// always-@(edge) statement.
      ExpEdge*edge = new ExpEdge(op2b->value()=='1'? ExpEdge::POSEDGE : ExpEdge::NEGEDGE, se);
      assert(sensitivity_list_.size() == 1);
      sensitivity_list_.pop_front();
      sensitivity_list_.push_front(edge);

	// Replace the statement with the body of the always
	// statement, which is the true clause of the top "if"
	// statement. There should be no "else" clause.
      assert(statements_list_.size() == 1);
      statements_list_.pop_front();

      stmt->extract_true(statements_list_);

      delete stmt;

      return 0;
}

/*
 * Change the "process (<expr>) <stmt>" into "always @(<expr>) ..."
 */
int ProcessStatement::extract_anyedge_(Entity*, Architecture*)
{

      vector<Expression*> se;
      while (! sensitivity_list_.empty()) {
	    se.push_back(sensitivity_list_.front());
	    sensitivity_list_.pop_front();
      }

      for (size_t idx = 0 ; idx < se.size() ; idx += 1) {
	    ExpEdge*edge = new ExpEdge(ExpEdge::ANYEDGE, se[idx]);
	    FILE_NAME(edge, se[idx]);
	    sensitivity_list_.push_back(edge);
      }

      return 0;
}

int ProcessStatement::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;

      if (rewrite_as_always_edge_(ent, arc) >= 0) {

      } else if (extract_anyedge_(ent, arc) >= 0) {

      } else {
      }

      for (list<SequentialStmt*>::iterator cur = statements_list_.begin()
		 ; cur != statements_list_.end() ; ++cur) {
	    errors += (*cur)->elaborate(ent, arc);
      }

      return errors;
}

int SignalAssignment::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;

	// Elaborate the l-value expression.
      errors += lval_->elaborate_lval(ent, arc, false);

	// The elaborate_lval should have resolved the type of the
	// l-value expression. We'll use that type to elaborate the
	// r-value.
      const VType*lval_type = lval_->peek_type();
      if (lval_type == 0) {
	    if (errors == 0) {
		  errors += 1;
		  cerr << get_fileline() << ": error: Unable to calculate type for l-value expression." << endl;
	    }
	    return errors;
      }

      for (list<Expression*>::iterator cur = rval_.begin()
		 ; cur != rval_.end() ; ++cur) {
	    (*cur)->elaborate_expr(ent, arc, lval_type);

            // Handle functions that return unbounded arrays
      }

      return errors;
}
<commit_msg>vhdlpp: Unnecessary comment.<commit_after>/*
 * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
 *
 *    This source code is free software; you can redistribute it
 *    and/or modify it in source code form under the terms of the GNU
 *    General Public License as published by the Free Software
 *    Foundation; either version 2 of the License, or (at your option)
 *    any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

# include  "architec.h"
# include  "entity.h"
# include  "expression.h"
# include  "sequential.h"
# include  <typeinfo>
# include  <cassert>

int Architecture::elaborate(Entity*entity)
{
      int errors = 0;

	// Constant assignments in the architecture get their types
	// from the constant declaration itself. Elaborate the value
	// expression with the declared type.

      for (map<perm_string,struct const_t*>::iterator cur = use_constants_.begin()
		 ; cur != use_constants_.end() ; ++cur) {
	    cur->second->val->elaborate_expr(entity, this, cur->second->typ);
      }
      for (map<perm_string,struct const_t*>::iterator cur = cur_constants_.begin()
		 ; cur != cur_constants_.end() ; ++cur) {
	    cur->second->val->elaborate_expr(entity, this, cur->second->typ);
      }

        // Elaborate initializer expressions for signals & variables
      for (map<perm_string,Signal*>::iterator cur = old_signals_.begin()
		 ; cur != old_signals_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }
      for (map<perm_string,Signal*>::iterator cur = new_signals_.begin()
		 ; cur != new_signals_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }
      for (map<perm_string,Variable*>::iterator cur = old_variables_.begin()
		 ; cur != old_variables_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }
      for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
		 ; cur != new_variables_.end() ; ++cur) {
	    cur->second->elaborate_init_expr(entity, this);
      }

      for (list<Architecture::Statement*>::iterator cur = statements_.begin()
		 ; cur != statements_.end() ; ++cur) {

	    int cur_errors = (*cur)->elaborate(entity, this);
	    errors += cur_errors;
      }

      if (errors > 0) {
	    cerr << errors << " errors in "
		 << name_ << " architecture of "
		 << entity->get_name() << "." << endl;
      }

      return errors;
}

int Architecture::Statement::elaborate(Entity*, Architecture*)
{
      return 0;
}

int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;

      ComponentBase*base = arc->find_component(cname_);
      if (base == 0) {
	    cerr << get_fileline() << ": error: No component declaration"
		 << " for instance " << iname_
		 << " of " << cname_ << "." << endl;
	    return 1;
      }

      for (map<perm_string,Expression*>::const_iterator cur = generic_map_.begin()
		 ; cur != generic_map_.end() ; ++cur) {
	      // check if generic from component instantiation
	      // exists in the component declaration
	    const InterfacePort*iparm = base->find_generic(cur->first);
	    if (iparm == 0) {
		  cerr << get_fileline() << ": warning: No generic " << cur->first
		       << " in component " << cname_ << "." << endl;
		  continue;
	    }

	    ExpName* tmp;
	    if (cur->second && (tmp = dynamic_cast<ExpName*>(cur->second)))
		  errors += tmp->elaborate_rval(ent, arc, iparm);

	    if (cur->second)
		  errors += cur->second->elaborate_expr(ent, arc, iparm->type);
      }

      for (map<perm_string,Expression*>::const_iterator cur = port_map_.begin()
		 ; cur != port_map_.end() ; ++cur) {
	      // check if a port from component instantiation
	      // exists in the component declaration
	    const InterfacePort*iport = base->find_port(cur->first);
	    if (iport == 0) {
		  cerr << get_fileline() << ": error: No port " << cur->first
		       << " in component " << cname_ << "." << endl;
		  errors += 1;
		  continue;
	    }

	    ExpName* tmp;
	    if (cur->second && (tmp = dynamic_cast<ExpName*>(cur->second)))
		  errors += tmp->elaborate_rval(ent, arc, iport);
	      /* It is possible for the port to be explicitly
		 unconnected. In that case, the Expression will be nil */

	    if (cur->second)
		  cur->second->elaborate_expr(ent, arc, iport->type);
      }

      return errors;
}

int GenerateStatement::elaborate_statements(Entity*ent, Architecture*arc)
{
      int errors = 0;
      for (list<Architecture::Statement*>::iterator cur = statements_.begin()
		 ; cur != statements_.end() ; ++cur) {
	    Architecture::Statement*curp = *cur;
	    errors += curp->elaborate(ent, arc);
      }
      return errors;
}

int ForGenerate::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;
      arc->push_genvar_type(genvar_, lsb_->probe_type(ent, arc));
      errors += elaborate_statements(ent, arc);
      arc->pop_genvar_type();
      return errors;
}

int IfGenerate::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;
      errors += elaborate_statements(ent, arc);
      return errors;
}

/*
 * This method attempts to rewrite the process content as an
 * always-@(n-edge <expr>) version of the same statement. This makes
 * for a more natural translation to Verilog, if it comes to that.
 */
int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
{
	// If there are multiple sensitivity expressions, I give up.
      if (sensitivity_list_.size() != 1)
	    return -1;

	// If there are multiple statements, I give up.
      if (statements_list_.size() != 1)
	    return -1;

      Expression*se = sensitivity_list_.front();
      SequentialStmt*stmt_raw = statements_list_.front();

	// If the statement is not an if-statement, I give up.
      IfSequential*stmt = dynamic_cast<IfSequential*> (stmt_raw);
      if (stmt == 0)
	    return -1;

	// If the "if" statement has a false clause, then give up.
      if (stmt->false_size() != 0)
	    return -1;

      const Expression*ce_raw = stmt->peek_condition();
	// Now we have matched this pattern:
	//   process(<expr>) begin if <ce_raw>...
	// The <ce_raw> is the condition.

      if (const ExpFunc*ce_func = dynamic_cast<const ExpFunc*>(ce_raw)) {
	    if (ce_func->func_args() != 1)
		  return -1;
	    if (ce_func->func_name()!="rising_edge" && ce_func->func_name()!="falling_edge")
		  return -1;

	    if (! se->symbolic_compare(ce_func->func_arg(0)))
		return -1;

	      // We've matched this pattern:
	      //  process(<se>) if (rising_edge(<se>)) then ...
	      // and we can convert it to:
	      //  always @(posedge <se>) ...

	    ExpEdge::fun_t use_edge;
	    if (ce_func->func_name()=="rising_edge")
		  use_edge = ExpEdge::POSEDGE;
	    else if (ce_func->func_name()=="falling_edge")
		  use_edge = ExpEdge::NEGEDGE;
	    else
		  use_edge = ExpEdge::ANYEDGE;

	      // Replace the sensitivity expression with an edge
	      // expression. The ExpEdge expression signals that this
	      // is an always-@(edge) statement.
	    ExpEdge*edge = new ExpEdge(use_edge, se);
	    assert(sensitivity_list_.size() == 1);
	    sensitivity_list_.pop_front();
	    sensitivity_list_.push_front(edge);

	      // Replace the statement with the body of the always
	      // statement, which is the true clause of the top "if"
	      // statement. There should be no "else" clause.
	    assert(statements_list_.size() == 1);
	    statements_list_.pop_front();
	    stmt->extract_true(statements_list_);

	    delete stmt;
	    return 0;
      }

	// Here we expect the condition to be
	//    <name>'event AND <name>='1'.
	// So if ce_raw is not a logical AND, I give up.
      const ExpLogical*ce = dynamic_cast<const ExpLogical*> (ce_raw);
      if (ce == 0)
	    return -1;
      if (ce->logic_fun() != ExpLogical::AND)
	    return -1;

      const Expression*op1_raw = ce->peek_operand1();
      const Expression*op2_raw = ce->peek_operand2();
      if (dynamic_cast<const ExpAttribute*>(op2_raw)) {
	    const Expression*tmp = op1_raw;
	    op1_raw = op2_raw;
	    op2_raw = tmp;
      }

	// If operand1 is not an 'event attribute, I give up.
      const ExpAttribute*op1 = dynamic_cast<const ExpAttribute*>(op1_raw);
      if (op1 == 0)
	    return -1;
      if (op1->peek_attribute() != "event")
	    return -1;

      const ExpRelation*op2 = dynamic_cast<const ExpRelation*>(op2_raw);
      if (op2 == 0)
	    return -1;
      if (op2->relation_fun() != ExpRelation::EQ)
	    return -1;

      const Expression*op2a_raw = op2->peek_operand1();
      const Expression*op2b_raw = op2->peek_operand2();

      if (dynamic_cast<const ExpCharacter*>(op2a_raw)) {
	    const Expression*tmp = op2b_raw;
	    op2b_raw = op2a_raw;
	    op2a_raw = tmp;
      }

      if (! se->symbolic_compare(op1->peek_base()))
	    return -1;

      const ExpCharacter*op2b = dynamic_cast<const ExpCharacter*>(op2b_raw);
      if (op2b->value() != '1' && op2b->value() != '0')
	    return -1;

	// We've matched this pattern:
	//   process (<se>) if (<se>'event and <se> = <op2b>) then ...
	// And we can convert it to:
	//   always @(<N>edge <se>) ...

	// Replace the sensitivity expression with an edge
	// expression. The ExpEdge expression signals that this is an
	// always-@(edge) statement.
      ExpEdge*edge = new ExpEdge(op2b->value()=='1'? ExpEdge::POSEDGE : ExpEdge::NEGEDGE, se);
      assert(sensitivity_list_.size() == 1);
      sensitivity_list_.pop_front();
      sensitivity_list_.push_front(edge);

	// Replace the statement with the body of the always
	// statement, which is the true clause of the top "if"
	// statement. There should be no "else" clause.
      assert(statements_list_.size() == 1);
      statements_list_.pop_front();

      stmt->extract_true(statements_list_);

      delete stmt;

      return 0;
}

/*
 * Change the "process (<expr>) <stmt>" into "always @(<expr>) ..."
 */
int ProcessStatement::extract_anyedge_(Entity*, Architecture*)
{

      vector<Expression*> se;
      while (! sensitivity_list_.empty()) {
	    se.push_back(sensitivity_list_.front());
	    sensitivity_list_.pop_front();
      }

      for (size_t idx = 0 ; idx < se.size() ; idx += 1) {
	    ExpEdge*edge = new ExpEdge(ExpEdge::ANYEDGE, se[idx]);
	    FILE_NAME(edge, se[idx]);
	    sensitivity_list_.push_back(edge);
      }

      return 0;
}

int ProcessStatement::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;

      if (rewrite_as_always_edge_(ent, arc) >= 0) {

      } else if (extract_anyedge_(ent, arc) >= 0) {

      } else {
      }

      for (list<SequentialStmt*>::iterator cur = statements_list_.begin()
		 ; cur != statements_list_.end() ; ++cur) {
	    errors += (*cur)->elaborate(ent, arc);
      }

      return errors;
}

int SignalAssignment::elaborate(Entity*ent, Architecture*arc)
{
      int errors = 0;

	// Elaborate the l-value expression.
      errors += lval_->elaborate_lval(ent, arc, false);

	// The elaborate_lval should have resolved the type of the
	// l-value expression. We'll use that type to elaborate the
	// r-value.
      const VType*lval_type = lval_->peek_type();
      if (lval_type == 0) {
	    if (errors == 0) {
		  errors += 1;
		  cerr << get_fileline() << ": error: Unable to calculate type for l-value expression." << endl;
	    }
	    return errors;
      }

      for (list<Expression*>::iterator cur = rval_.begin()
		 ; cur != rval_.end() ; ++cur) {
	    (*cur)->elaborate_expr(ent, arc, lval_type);
      }

      return errors;
}
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file Style.cxx
 ** Defines the font and colour style for a class of text.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "Style.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

FontAlias::FontAlias() {
}

FontAlias::FontAlias(const FontAlias &other) {
	SetID(other.fid);
}

FontAlias::~FontAlias() {
	SetID(0);
	// ~Font will not release the actual font resource since it is now 0
}

void FontAlias::MakeAlias(Font &fontOrigin) {
	SetID(fontOrigin.GetID());
}

void FontAlias::ClearFont() {
	SetID(0);
}

bool FontSpecification::operator==(const FontSpecification &other) const {
	return fontName == other.fontName &&
	       weight == other.weight &&
	       italic == other.italic &&
	       size == other.size &&
	       characterSet == other.characterSet &&
	       extraFontFlag == other.extraFontFlag;
}

bool FontSpecification::operator<(const FontSpecification &other) const {
	if (fontName != other.fontName)
		return fontName < other.fontName;
	if (weight != other.weight)
		return weight < other.weight;
	if (italic != other.italic)
		return italic == false;
	if (size != other.size)
		return size < other.size;
	if (characterSet != other.characterSet)
		return characterSet < other.characterSet;
	if (extraFontFlag != other.extraFontFlag)
		return extraFontFlag < other.extraFontFlag;
	return false;
}

FontMeasurements::FontMeasurements() {
	Clear();
}

void FontMeasurements::Clear() {
	ascent = 1;
	descent = 1;
	aveCharWidth = 1;
	spaceWidth = 1;
	sizeZoomed = 2;
}

Style::Style() : FontSpecification() {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, 0, SC_CHARSET_DEFAULT,
	      SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false);
}

Style::Style(const Style &source) : FontSpecification(), FontMeasurements() {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, 0,
	      SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false);
	fore = source.fore;
	back = source.back;
	characterSet = source.characterSet;
	weight = source.weight;
	italic = source.italic;
	size = source.size;
	fontName = source.fontName;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	hotspot = source.hotspot;
}

Style::~Style() {
}

Style &Style::operator=(const Style &source) {
	if (this == &source)
		return * this;
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, SC_CHARSET_DEFAULT,
	      SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false);
	fore = source.fore;
	back = source.back;
	characterSet = source.characterSet;
	weight = source.weight;
	italic = source.italic;
	size = source.size;
	fontName = source.fontName;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	return *this;
}

void Style::Clear(ColourDesired fore_, ColourDesired back_, int size_,
        const char *fontName_, int characterSet_,
        int weight_, bool italic_, bool eolFilled_,
        bool underline_, ecaseForced caseForce_,
        bool visible_, bool changeable_, bool hotspot_) {
	fore = fore_;
	back = back_;
	characterSet = characterSet_;
	weight = weight_;
	italic = italic_;
	size = size_;
	fontName = fontName_;
	eolFilled = eolFilled_;
	underline = underline_;
	caseForce = caseForce_;
	visible = visible_;
	changeable = changeable_;
	hotspot = hotspot_;
	font.ClearFont();
	FontMeasurements::Clear();
}

void Style::ClearTo(const Style &source) {
	Clear(
	    source.fore,
	    source.back,
	    source.size,
	    source.fontName,
	    source.characterSet,
	    source.weight,
	    source.italic,
	    source.eolFilled,
	    source.underline,
	    source.caseForce,
	    source.visible,
	    source.changeable,
	    source.hotspot);
}

void Style::Copy(Font &font_, const FontMeasurements &fm_) {
	font.MakeAlias(font_);
#if PLAT_WX
	font.SetAscent(fm_.ascent);
#endif
	(FontMeasurements &)(*this) = fm_;
}
<commit_msg>Avoid warning from g++.<commit_after>// Scintilla source code edit control
/** @file Style.cxx
 ** Defines the font and colour style for a class of text.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <string.h>

#include "Platform.h"

#include "Scintilla.h"
#include "Style.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

FontAlias::FontAlias() {
}

FontAlias::FontAlias(const FontAlias &other) : Font() {
	SetID(other.fid);
}

FontAlias::~FontAlias() {
	SetID(0);
	// ~Font will not release the actual font resource since it is now 0
}

void FontAlias::MakeAlias(Font &fontOrigin) {
	SetID(fontOrigin.GetID());
}

void FontAlias::ClearFont() {
	SetID(0);
}

bool FontSpecification::operator==(const FontSpecification &other) const {
	return fontName == other.fontName &&
	       weight == other.weight &&
	       italic == other.italic &&
	       size == other.size &&
	       characterSet == other.characterSet &&
	       extraFontFlag == other.extraFontFlag;
}

bool FontSpecification::operator<(const FontSpecification &other) const {
	if (fontName != other.fontName)
		return fontName < other.fontName;
	if (weight != other.weight)
		return weight < other.weight;
	if (italic != other.italic)
		return italic == false;
	if (size != other.size)
		return size < other.size;
	if (characterSet != other.characterSet)
		return characterSet < other.characterSet;
	if (extraFontFlag != other.extraFontFlag)
		return extraFontFlag < other.extraFontFlag;
	return false;
}

FontMeasurements::FontMeasurements() {
	Clear();
}

void FontMeasurements::Clear() {
	ascent = 1;
	descent = 1;
	aveCharWidth = 1;
	spaceWidth = 1;
	sizeZoomed = 2;
}

Style::Style() : FontSpecification() {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      Platform::DefaultFontSize() * SC_FONT_SIZE_MULTIPLIER, 0, SC_CHARSET_DEFAULT,
	      SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false);
}

Style::Style(const Style &source) : FontSpecification(), FontMeasurements() {
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, 0,
	      SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false);
	fore = source.fore;
	back = source.back;
	characterSet = source.characterSet;
	weight = source.weight;
	italic = source.italic;
	size = source.size;
	fontName = source.fontName;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	hotspot = source.hotspot;
}

Style::~Style() {
}

Style &Style::operator=(const Style &source) {
	if (this == &source)
		return * this;
	Clear(ColourDesired(0, 0, 0), ColourDesired(0xff, 0xff, 0xff),
	      0, 0, SC_CHARSET_DEFAULT,
	      SC_WEIGHT_NORMAL, false, false, false, caseMixed, true, true, false);
	fore = source.fore;
	back = source.back;
	characterSet = source.characterSet;
	weight = source.weight;
	italic = source.italic;
	size = source.size;
	fontName = source.fontName;
	eolFilled = source.eolFilled;
	underline = source.underline;
	caseForce = source.caseForce;
	visible = source.visible;
	changeable = source.changeable;
	return *this;
}

void Style::Clear(ColourDesired fore_, ColourDesired back_, int size_,
        const char *fontName_, int characterSet_,
        int weight_, bool italic_, bool eolFilled_,
        bool underline_, ecaseForced caseForce_,
        bool visible_, bool changeable_, bool hotspot_) {
	fore = fore_;
	back = back_;
	characterSet = characterSet_;
	weight = weight_;
	italic = italic_;
	size = size_;
	fontName = fontName_;
	eolFilled = eolFilled_;
	underline = underline_;
	caseForce = caseForce_;
	visible = visible_;
	changeable = changeable_;
	hotspot = hotspot_;
	font.ClearFont();
	FontMeasurements::Clear();
}

void Style::ClearTo(const Style &source) {
	Clear(
	    source.fore,
	    source.back,
	    source.size,
	    source.fontName,
	    source.characterSet,
	    source.weight,
	    source.italic,
	    source.eolFilled,
	    source.underline,
	    source.caseForce,
	    source.visible,
	    source.changeable,
	    source.hotspot);
}

void Style::Copy(Font &font_, const FontMeasurements &fm_) {
	font.MakeAlias(font_);
#if PLAT_WX
	font.SetAscent(fm_.ascent);
#endif
	(FontMeasurements &)(*this) = fm_;
}
<|endoftext|>


<commit_before>#include "ffmpegdecoder.h"
#include "makeguard.h"
#include "interlockedadd.h"

#include <boost/log/trivial.hpp>

#include <functional>
#include <memory>
#include <tuple>

namespace {

uint8_t** getAudioData(AVFrame* audioFrame)
{
    return audioFrame->extended_data != nullptr
        ? audioFrame->extended_data
        : &audioFrame->data[0];
}

int64_t getChannelLayout(AVFrame* audioFrame)
{
	const int audioFrameChannels = audioFrame->channels; //av_frame_get_channels(audioFrame);
    return ((audioFrame->channel_layout != 0u) &&
        audioFrameChannels == av_get_channel_layout_nb_channels(audioFrame->channel_layout))
        ? audioFrame->channel_layout
        : av_get_default_channel_layout(audioFrameChannels);
}

} // namespace

void FFmpegDecoder::audioParseRunnable()
{
    CHANNEL_LOG(ffmpeg_threads) << "Audio thread started";
    AVPacket packet;

    bool initialized = false;
    bool failed = false;

    m_audioPlayer->InitializeThread();
    auto deinitializeThread = MakeGuard(
        m_audioPlayer.get(),
        std::mem_fn(&IAudioPlayer::DeinitializeThread));

    std::vector<uint8_t> resampleBuffer;

    double scheduledEndTime = 0;

    auto useHandleAudioResultLam = [this, &failed](bool result)
    {
        if (result)
        {
            if (failed)
            {
                failed = false;
                boost::lock_guard<boost::mutex> locker(m_isPausedMutex);
                if (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                {
                    m_audioPTS = (m_isPaused ? m_pauseTimer : GetHiResTime()) - m_videoStartClock;
                }
            }
        }
        else
        {
            failed = true;
        }
    };

    while (!boost::this_thread::interruption_requested())
    {
        if (!m_audioPacketsQueue.pop(packet))
        {
            break;
        }

        auto packetGuard = MakeGuard(&packet, av_packet_unref);

        if (m_audioStreamNumber != packet.stream_index)
        {
            continue;
        }

        if (!initialized)
        {
            if (packet.pts == AV_NOPTS_VALUE)
            {
                if (packet.data == nullptr)
                    continue;

                assert(false && "No audio pts found");
                return;
            }
            const double pts = av_q2d(m_audioStream->time_base) * packet.pts;
            m_audioPTS = pts;
            scheduledEndTime = pts;
            // invoke changedFramePosition() if needed
            //AppendFrameClock(0);
        }
        else if (packet.pts != AV_NOPTS_VALUE)
        {
            const double diff = av_q2d(m_audioStream->time_base) * packet.pts - scheduledEndTime;
            if (diff > 0.01)
            {
                CHANNEL_LOG(ffmpeg_sync) << "Patching audio frame diff: " << diff;
                if (m_formatContexts.size() == 1 && m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                {
                    InterlockedAdd(m_videoStartClock, -diff);
                    InterlockedAdd(m_audioPTS, diff);
                }
                else
                {
                    const int size_multiplier = m_audioSettings.channels *
                        av_get_bytes_per_sample(m_audioSettings.format);

                    const int numSteps = (diff + 0.1) / 0.1;
                    const auto frame_clock = diff / numSteps;
                    for (int i = 0; i < numSteps; ++i)
                    {
                        const auto speed = getSpeedRational();
                        const int nb_samples = frame_clock * m_audioSettings.frequency * speed.denominator / speed.numerator;
                        const auto write_size = nb_samples * size_multiplier;
                        std::vector<uint8_t> buf(write_size, 0);
                        useHandleAudioResultLam(handleAudioFrame(frame_clock, buf.data(), write_size, failed));
                    }
                }
            }

            scheduledEndTime += diff;
        }

        initialized = true;

        useHandleAudioResultLam(handleAudioPacket(packet, resampleBuffer, failed, scheduledEndTime));
    }
}

bool FFmpegDecoder::handleAudioPacket(
    const AVPacket& packet,
    std::vector<uint8_t>& resampleBuffer,
    bool failed, double& scheduledEndTime)
{
    if (packet.stream_index != m_audioStream->index)
    {
        avcodec_close(m_audioCodecContext);
        m_audioStream = m_formatContexts[m_audioContextIndex]->streams[packet.stream_index];
        if (!setupAudioCodec())
        {
            return false;
        }
    }

    const int ret = avcodec_send_packet(m_audioCodecContext, &packet);
    if (ret < 0) {
        return ret == AVERROR(EAGAIN) || ret == AVERROR_EOF;
    }

    AVFramePtr audioFrame(av_frame_alloc());
    bool result = true;
    while (avcodec_receive_frame(m_audioCodecContext, audioFrame.get()) == 0)
    {
        if (audioFrame->nb_samples <= 0)
        {
            continue;
        }

        const int original_buffer_size = av_samples_get_buffer_size(
            nullptr, audioFrame->channels,
            audioFrame->nb_samples,
            static_cast<AVSampleFormat>(audioFrame->format), 1);

        // write buffer
        uint8_t* write_data = *getAudioData(audioFrame.get());
        int64_t write_size = original_buffer_size;

        setupAudioSwrContext(audioFrame.get());

        if (m_audioSwrContext != nullptr)
        {
            enum { EXTRA_SPACE = 256 };

            const int out_count = static_cast<int64_t>(audioFrame->nb_samples) *
                m_audioSettings.frequency /
                m_audioCurrentPref.frequency + EXTRA_SPACE;

            const int size_multiplier = m_audioSettings.channels *
                av_get_bytes_per_sample(m_audioSettings.format);

            const size_t buffer_size = out_count * size_multiplier;

            if (resampleBuffer.size() < buffer_size)
            {
                resampleBuffer.resize(buffer_size);
            }

            // Code for resampling
            uint8_t *out = resampleBuffer.data();
            const int converted_size = swr_convert(
                m_audioSwrContext,
                &out,
                out_count,
                const_cast<const uint8_t**>(getAudioData(audioFrame.get())),
                audioFrame->nb_samples);

            if (converted_size < 0)
            {
                BOOST_LOG_TRIVIAL(error) << "swr_convert() failed";
                break;
            }

            if (converted_size == out_count)
            {
                BOOST_LOG_TRIVIAL(warning) << "audio buffer is probably too small";
                swr_init(m_audioSwrContext);
            }

            write_data = out;
            write_size = converted_size * size_multiplier;

            assert(write_size < buffer_size);
        }

        const double frame_clock
            = audioFrame->sample_rate != 0? double(audioFrame->nb_samples) / audioFrame->sample_rate : 0;

        scheduledEndTime += frame_clock;

        if (!handleAudioFrame(frame_clock, write_data, write_size, failed))
        {
            result = false;
        }
    }

    return result;
}

void FFmpegDecoder::setupAudioSwrContext(AVFrame* audioFrame)
{
    const auto audioFrameFormat = static_cast<AVSampleFormat>(audioFrame->format);
    const int audioFrameChannels = audioFrame->channels;

    const int64_t dec_channel_layout = getChannelLayout(audioFrame);

    const auto speed = getSpeedRational();

    // Check if the new swr context required
    if (audioFrameFormat != m_audioCurrentPref.format ||
        dec_channel_layout != m_audioCurrentPref.channel_layout ||
        (audioFrame->sample_rate * speed.numerator) / speed.denominator != m_audioCurrentPref.frequency)
    {
        swr_free(&m_audioSwrContext);
        m_audioSwrContext = swr_alloc_set_opts(
            nullptr, m_audioSettings.channel_layout, m_audioSettings.format,
            m_audioSettings.frequency * speed.denominator,
            dec_channel_layout, audioFrameFormat,
            audioFrame->sample_rate * speed.numerator, 0, nullptr);

        if ((m_audioSwrContext == nullptr) || swr_init(m_audioSwrContext) < 0)
        {
            BOOST_LOG_TRIVIAL(error) << "unable to initialize swr convert context";
        }

        m_audioCurrentPref.format = audioFrameFormat;
        m_audioCurrentPref.channels = audioFrameChannels;
        m_audioCurrentPref.channel_layout = dec_channel_layout;
        m_audioCurrentPref.frequency = (audioFrame->sample_rate * speed.numerator) / speed.denominator;
    }
}

bool FFmpegDecoder::handleAudioFrame(
    double frame_clock, uint8_t* write_data, int64_t write_size, bool failed)
{
    bool skipAll = false;
    double delta = 0;
    bool isPaused = false;

    {
        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);
        isPaused = m_isPaused;
        if (!isPaused)
        {
            delta = (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                ? GetHiResTime() - m_videoStartClock - m_audioPTS : 0;
        }
    }

    if (isPaused)
    {
        if (!m_audioPaused)
        {
            m_audioPlayer->WaveOutPause();
            m_audioPaused = true;
        }

        const bool hasVideo = m_mainVideoThread != nullptr;

        boost::unique_lock<boost::mutex> locker(m_isPausedMutex);

        while (m_isVideoSeekingWhilePaused && hasVideo
            || (delta = (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                ? (m_isPaused ? m_pauseTimer : GetHiResTime()) - m_videoStartClock - m_audioPTS : 0
                , m_isPaused && !(skipAll = delta >= frame_clock)))
        {
            m_isPausedCV.wait(locker);
        }
    }
    else if (delta > 1 && m_formatContexts.size() > 1 && delta > frame_clock)
    {
        CHANNEL_LOG(ffmpeg_sync) << "Skip audio frame";
        skipAll = true;
    }

    // Audio sync
    if (!failed && !skipAll && fabs(delta) > 0.1)
    {
        CHANNEL_LOG(ffmpeg_sync) << "Audio sync delta = " << delta;
        InterlockedAdd(m_videoStartClock, delta / 2);
    }

    if (m_audioPaused && !skipAll)
    {
        m_audioPlayer->WaveOutRestart();
        m_audioPaused = false;
    }

    boost::this_thread::interruption_point();

    if (skipAll)
    {
        InterlockedAdd(m_audioPTS, frame_clock);
    }
    else if (!(m_audioPlayer->WriteAudio(write_data, write_size)
        || initAudioOutput() && m_audioPlayer->WriteAudio(write_data, write_size)))
    {
        return false;
    }

    return true;
}
<commit_msg>audio past video case fixed<commit_after>#include "ffmpegdecoder.h"
#include "makeguard.h"
#include "interlockedadd.h"

#include <boost/log/trivial.hpp>

#include <algorithm>
#include <functional>
#include <memory>
#include <tuple>

namespace {

uint8_t** getAudioData(AVFrame* audioFrame)
{
    return audioFrame->extended_data != nullptr
        ? audioFrame->extended_data
        : &audioFrame->data[0];
}

int64_t getChannelLayout(AVFrame* audioFrame)
{
	const int audioFrameChannels = audioFrame->channels; //av_frame_get_channels(audioFrame);
    return ((audioFrame->channel_layout != 0u) &&
        audioFrameChannels == av_get_channel_layout_nb_channels(audioFrame->channel_layout))
        ? audioFrame->channel_layout
        : av_get_default_channel_layout(audioFrameChannels);
}

} // namespace

void FFmpegDecoder::audioParseRunnable()
{
    CHANNEL_LOG(ffmpeg_threads) << "Audio thread started";
    AVPacket packet;

    bool initialized = false;
    bool failed = false;

    m_audioPlayer->InitializeThread();
    auto deinitializeThread = MakeGuard(
        m_audioPlayer.get(),
        std::mem_fn(&IAudioPlayer::DeinitializeThread));

    std::vector<uint8_t> resampleBuffer;

    double scheduledEndTime = 0;

    auto useHandleAudioResultLam = [this, &failed](bool result)
    {
        if (result)
        {
            if (failed)
            {
                failed = false;
                boost::lock_guard<boost::mutex> locker(m_isPausedMutex);
                if (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                {
                    m_audioPTS = (m_isPaused ? m_pauseTimer : GetHiResTime()) - m_videoStartClock;
                }
            }
        }
        else
        {
            failed = true;
        }
    };

    while (!boost::this_thread::interruption_requested())
    {
        if (!m_audioPacketsQueue.pop(packet))
        {
            break;
        }

        auto packetGuard = MakeGuard(&packet, av_packet_unref);

        if (m_audioStreamNumber != packet.stream_index)
        {
            continue;
        }

        if (!initialized)
        {
            if (packet.pts == AV_NOPTS_VALUE)
            {
                if (packet.data == nullptr)
                    continue;

                assert(false && "No audio pts found");
                return;
            }
            const double pts = av_q2d(m_audioStream->time_base) * packet.pts;
            m_audioPTS = pts;
            scheduledEndTime = pts;
            // invoke changedFramePosition() if needed
            //AppendFrameClock(0);
        }
        else if (packet.pts != AV_NOPTS_VALUE)
        {
            const double diff = av_q2d(m_audioStream->time_base) * packet.pts - scheduledEndTime;
            if (diff > 0.01)
            {
                CHANNEL_LOG(ffmpeg_sync) << "Patching audio frame diff: " << diff;
                if (m_formatContexts.size() == 1 && m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                {
                    InterlockedAdd(m_videoStartClock, -diff);
                    InterlockedAdd(m_audioPTS, diff);
                }
                else
                {
                    const int size_multiplier = m_audioSettings.channels *
                        av_get_bytes_per_sample(m_audioSettings.format);

                    const int numSteps = (diff + 0.1) / 0.1;
                    const auto frame_clock = diff / numSteps;
                    for (int i = 0; i < numSteps; ++i)
                    {
                        const auto speed = getSpeedRational();
                        const int nb_samples = frame_clock * m_audioSettings.frequency * speed.denominator / speed.numerator;
                        const auto write_size = nb_samples * size_multiplier;
                        std::vector<uint8_t> buf(write_size, 0);
                        useHandleAudioResultLam(handleAudioFrame(frame_clock, buf.data(), write_size, failed));
                    }
                }
            }

            scheduledEndTime += diff;
        }

        initialized = true;

        useHandleAudioResultLam(handleAudioPacket(packet, resampleBuffer, failed, scheduledEndTime));
    }
}

bool FFmpegDecoder::handleAudioPacket(
    const AVPacket& packet,
    std::vector<uint8_t>& resampleBuffer,
    bool failed, double& scheduledEndTime)
{
    if (packet.stream_index != m_audioStream->index)
    {
        avcodec_close(m_audioCodecContext);
        m_audioStream = m_formatContexts[m_audioContextIndex]->streams[packet.stream_index];
        if (!setupAudioCodec())
        {
            return false;
        }
    }

    const int ret = avcodec_send_packet(m_audioCodecContext, &packet);
    if (ret < 0) {
        return ret == AVERROR(EAGAIN) || ret == AVERROR_EOF;
    }

    AVFramePtr audioFrame(av_frame_alloc());
    bool result = true;
    while (avcodec_receive_frame(m_audioCodecContext, audioFrame.get()) == 0)
    {
        if (audioFrame->nb_samples <= 0)
        {
            continue;
        }

        const int original_buffer_size = av_samples_get_buffer_size(
            nullptr, audioFrame->channels,
            audioFrame->nb_samples,
            static_cast<AVSampleFormat>(audioFrame->format), 1);

        // write buffer
        uint8_t* write_data = *getAudioData(audioFrame.get());
        int64_t write_size = original_buffer_size;

        setupAudioSwrContext(audioFrame.get());

        if (m_audioSwrContext != nullptr)
        {
            enum { EXTRA_SPACE = 256 };

            const int out_count = static_cast<int64_t>(audioFrame->nb_samples) *
                m_audioSettings.frequency /
                m_audioCurrentPref.frequency + EXTRA_SPACE;

            const int size_multiplier = m_audioSettings.channels *
                av_get_bytes_per_sample(m_audioSettings.format);

            const size_t buffer_size = out_count * size_multiplier;

            if (resampleBuffer.size() < buffer_size)
            {
                resampleBuffer.resize(buffer_size);
            }

            // Code for resampling
            uint8_t *out = resampleBuffer.data();
            const int converted_size = swr_convert(
                m_audioSwrContext,
                &out,
                out_count,
                const_cast<const uint8_t**>(getAudioData(audioFrame.get())),
                audioFrame->nb_samples);

            if (converted_size < 0)
            {
                BOOST_LOG_TRIVIAL(error) << "swr_convert() failed";
                break;
            }

            if (converted_size == out_count)
            {
                BOOST_LOG_TRIVIAL(warning) << "audio buffer is probably too small";
                swr_init(m_audioSwrContext);
            }

            write_data = out;
            write_size = converted_size * size_multiplier;

            assert(write_size < buffer_size);
        }

        const double frame_clock
            = audioFrame->sample_rate != 0? double(audioFrame->nb_samples) / audioFrame->sample_rate : 0;

        scheduledEndTime += frame_clock;

        if (!handleAudioFrame(frame_clock, write_data, write_size, failed))
        {
            result = false;
        }
    }

    return result;
}

void FFmpegDecoder::setupAudioSwrContext(AVFrame* audioFrame)
{
    const auto audioFrameFormat = static_cast<AVSampleFormat>(audioFrame->format);
    const int audioFrameChannels = audioFrame->channels;

    const int64_t dec_channel_layout = getChannelLayout(audioFrame);

    const auto speed = getSpeedRational();

    // Check if the new swr context required
    if (audioFrameFormat != m_audioCurrentPref.format ||
        dec_channel_layout != m_audioCurrentPref.channel_layout ||
        (audioFrame->sample_rate * speed.numerator) / speed.denominator != m_audioCurrentPref.frequency)
    {
        swr_free(&m_audioSwrContext);
        m_audioSwrContext = swr_alloc_set_opts(
            nullptr, m_audioSettings.channel_layout, m_audioSettings.format,
            m_audioSettings.frequency * speed.denominator,
            dec_channel_layout, audioFrameFormat,
            audioFrame->sample_rate * speed.numerator, 0, nullptr);

        if ((m_audioSwrContext == nullptr) || swr_init(m_audioSwrContext) < 0)
        {
            BOOST_LOG_TRIVIAL(error) << "unable to initialize swr convert context";
        }

        m_audioCurrentPref.format = audioFrameFormat;
        m_audioCurrentPref.channels = audioFrameChannels;
        m_audioCurrentPref.channel_layout = dec_channel_layout;
        m_audioCurrentPref.frequency = (audioFrame->sample_rate * speed.numerator) / speed.denominator;
    }
}

bool FFmpegDecoder::handleAudioFrame(
    double frame_clock, uint8_t* write_data, int64_t write_size, bool failed)
{
    bool skipAll = false;
    double delta = 0;
    bool isPaused = false;

    {
        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);
        isPaused = m_isPaused;
        if (!isPaused)
        {
            delta = (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                ? GetHiResTime() - m_videoStartClock - m_audioPTS : 0;
        }
    }

    if (isPaused)
    {
        if (!m_audioPaused)
        {
            m_audioPlayer->WaveOutPause();
            m_audioPaused = true;
        }

        const bool hasVideo = m_mainVideoThread != nullptr;

        boost::unique_lock<boost::mutex> locker(m_isPausedMutex);

        while (m_isVideoSeekingWhilePaused && hasVideo
            || (delta = (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)
                ? (m_isPaused ? m_pauseTimer : GetHiResTime()) - m_videoStartClock - m_audioPTS : 0
                , m_isPaused && !(skipAll = delta >= frame_clock)))
        {
            m_isPausedCV.wait(locker);
        }
    }
    else if (delta > 1 && m_formatContexts.size() > 1 && delta > frame_clock)
    {
        CHANNEL_LOG(ffmpeg_sync) << "Skip audio frame";
        skipAll = true;
    }

    if (!skipAll && m_mainVideoThread != nullptr
        && std::all_of(write_data, write_data + write_size, [](uint8_t data) { return data == 0; })
        && m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED
        && m_videoPacketsQueue.empty()
        && (boost::lock_guard<boost::mutex>(m_videoFramesMutex), !m_videoFramesQueue.canPop()))
    {
        return true; // just ignore?
    }

    // Audio sync
    if (!failed && !skipAll && fabs(delta) > 0.1)
    {
        CHANNEL_LOG(ffmpeg_sync) << "Audio sync delta = " << delta;
        InterlockedAdd(m_videoStartClock, delta / 2);
    }

    if (m_audioPaused && !skipAll)
    {
        m_audioPlayer->WaveOutRestart();
        m_audioPaused = false;
    }

    boost::this_thread::interruption_point();

    if (skipAll)
    {
        InterlockedAdd(m_audioPTS, frame_clock);
    }
    else if (!(m_audioPlayer->WriteAudio(write_data, write_size)
        || initAudioOutput() && m_audioPlayer->WriteAudio(write_data, write_size)))
    {
        return false;
    }

    return true;
}
<|endoftext|>


<commit_before>#ifndef UTILS_HPP
#define UTILS_HPP

#include <type_traits>
#include <utility>

////////////////////////// Tuple unpack utils
////////////////////////// http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer

namespace util
{
	// helper class
	template <
		typename F,
		typename... Args,
		std::size_t... I
	>
	auto call_helper(const F& func, const std::tuple<Args...> & params) -> std::result_of_t<F(Args...)>
	{
		return func(std::get<I>(params)...);
	}

	template<
		typename F,
		typename... Args
	>
	auto call(const F& func, const std::tuple<Args...> & params) -> std::result_of_t<F(Args...)>
	{
		return call_helper<F, Args..., std::index_sequence_for<Args...> >(func, params);
	}
}

////////////////////////// Bitflags enumerations
template <typename T> struct is_enum_flags : std::false_type
{
	//static_assert(std::is_enum<T>::value, "T must be an enum type");
};

////////////////////////// operator|
template <
	typename T,
	typename = std::enable_if_t<is_enum_flags<T>::value>
>
inline T operator|(T a, T b)
{
	return static_cast<T>(static_cast<std::underlying_type_t<T>>(a) | static_cast<std::underlying_type_t<T>>(b));
}

////////////////////////// operator|=
template <
	typename T,
	typename = std::enable_if_t<is_enum_flags<T>::value>
>
inline T& operator|=(T& a, T b)
{
	a = a | b;
	return a;
}

////////////////////////// operator&=
template <
	typename T,
	typename = std::enable_if_t<is_enum_flags<T>::value>
>
inline T operator&(T a, T b)
{
	return static_cast<T>(static_cast<std::underlying_type_t<T>>(a) & static_cast<std::underlying_type_t<T>>(b));
}

#endif // !UTILS_HPP
<commit_msg>Fix Utils.hpp call_helper<commit_after>#ifndef UTILS_HPP
#define UTILS_HPP

#include <type_traits>
#include <utility>

////////////////////////// Tuple unpack utils
////////////////////////// http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer

namespace util
{
	// helper class
	template <
		typename F,
		typename... Args,
		std::size_t... I
	>
	auto call_helper(const F& func, const std::tuple<Args...> & params, std::index_sequence<I>) -> std::result_of_t<F(Args...)>
	{
		return func(std::get<I>(params)...);
	}

	template<
		typename F,
		typename... Args
	>
	auto call(const F& func, const std::tuple<Args...> & params) -> std::result_of_t<F(Args...)>
	{
		return call_helper<F, Args...>(func, params, std::index_sequence_for<Args...>);
	}
}

////////////////////////// Bitflags enumerations
template <typename T> struct is_enum_flags : std::false_type
{
	//static_assert(std::is_enum<T>::value, "T must be an enum type");
};

////////////////////////// operator|
template <
	typename T,
	typename = std::enable_if_t<is_enum_flags<T>::value>
>
inline T operator|(T a, T b)
{
	return static_cast<T>(static_cast<std::underlying_type_t<T>>(a) | static_cast<std::underlying_type_t<T>>(b));
}

////////////////////////// operator|=
template <
	typename T,
	typename = std::enable_if_t<is_enum_flags<T>::value>
>
inline T& operator|=(T& a, T b)
{
	a = a | b;
	return a;
}

////////////////////////// operator&=
template <
	typename T,
	typename = std::enable_if_t<is_enum_flags<T>::value>
>
inline T operator&(T a, T b)
{
	return static_cast<T>(static_cast<std::underlying_type_t<T>>(a) & static_cast<std::underlying_type_t<T>>(b));
}

#endif // !UTILS_HPP
<|endoftext|>


<commit_before>/* $Id: OutputFormat.C,v 1.17 1999-11-09 17:11:37 wilson Exp $ */
#include "OutputFormat.h"

#include "Input/CoolingTime.h"
#include "Input/Volume.h"
#include "Input/Mixture.h"
#include "Input/Loading.h"

#include "Chains/Node.h"

#define Bq2Ci 2.7027e-11
#define m32cm3 1e6

const char *Out_Types = "ucnstabgw";

const int nOutTypes = 9;
const int firstResponse = 2;
const int lastSingularResponse = 8;
const char *Out_Types_Str[nOutTypes] = {
  "Response Units",
  "Break-down by Component",
  "Number Density [atoms/%s]",
  "Specific Activity [%s/%s]",
  "Total Decay Heat [W/%s]",
  "Alpha Decay Heat [W/%s]",
  "Beta Decay Heat [W/%s]",
  "Gamma Decay Heat [W/%s]",
  "WDR/Clearance index"};

/***************************
 ********* Service *********
 **************************/

OutputFormat::OutputFormat(int type)
{
  resolution = type;
  outTypes = 0;
  actUnits = new char[3];
  strcpy(actUnits,"Bq");
  actMult = 1;

  normUnits = new char[4];
  strcpy(normUnits,"cm3");
  normMult = 1;

  next = NULL;
}

OutputFormat::OutputFormat(const OutputFormat& o) :
  resolution(o.resolution), outTypes(o.outTypes), actMult(o.actMult),
  normMult(o.normMult)
{
  actUnits = new char[strlen(o.actUnits)+1];
  strcpy(actUnits,o.actUnits);

  normUnits = new char[strlen(o.normUnits)+1];
  strcpy(normUnits,o.normUnits);

  next = NULL;
}

OutputFormat::~OutputFormat()
{
  delete actUnits;
  delete normUnits;
  delete next;
}

OutputFormat& OutputFormat::operator=(const OutputFormat& o)
{
  if (this == &o)
    return *this;

  resolution = o.resolution;
  outTypes = o.outTypes;
  delete actUnits;
  actUnits = new char[strlen(o.actUnits)+1];
  strcpy(actUnits,o.actUnits);
  actMult = o.actMult;

  delete normUnits;
  normUnits = new char[strlen(o.normUnits)+1];
  strcpy(normUnits,o.normUnits);
  normMult = o.normMult;

  return *this;
}

/***************************
 ********** Input **********
 **************************/

OutputFormat* OutputFormat::getOutFmts(istream& input)
{
  const char *Out_Res = " izm";

  int type;
  char token[64];
  char *fileNamePtr;

  input >> token;
  type = strchr(Out_Res,tolower(token[0]))-Out_Res;

  next = new OutputFormat(type);

  verbose(2,"Added output at resolution %d (%s)",type,token);

  /* read a list of output types until keyword "end" */
  clearComment(input);
  input >> token;
  while (strcmp(token,"end"))
    {
      /* match the first character of the type in the constant string */
      type = strchr(Out_Types,tolower(token[0]))-Out_Types;
      if (type<0)
	error(230,"Output type '%s' is not currently supported.",
	      token);

      /* use logical and to set the correct bit in the outTypes field */
      next->outTypes |= 1<<type;

      verbose(3,"Added output type %d (%s)",1<<type,token);

      switch (1<<type)
	{
	case OUTFMT_UNITS:
	  input >> token;
	  next->actUnits = new char[strlen(token)+1];
	  strcpy(next->actUnits,token);
	  next->actMult = (tolower(token[0]) == 'c'?Bq2Ci:1);

	  input >> token;
	  next->normUnits = new char[strlen(token)+1];
	  strcpy(next->normUnits,token);
	  next->normMult = (tolower(token[0]) == 'm'?m32cm3:1);
	  break;
	case OUTFMT_WDR:
	  input >> token;
	  fileNamePtr = new char[strlen(token)+1];
	  strcpy(fileNamePtr,token);
	  next->wdrFilenames.insert(fileNamePtr);
	  verbose(4,"Added WDR/Clearance file %s", token);
	}

      clearComment(input);
      input >> token;
    }

  return next;

}

void OutputFormat::write(Volume* volList, Mixture* mixList, Loading* loadList,
			 CoolingTime *coolList, int targetKza)
{

  OutputFormat *ptr = this;
  char buffer[64];

  int outTypeNum;

  /* for each output description */
  while (ptr->next != NULL)
    {

      ptr = ptr->next;

      /* write a header */
      switch(ptr->resolution)
	{
	case OUTRES_INT:
	  cout << "Interval output requested:"<< endl;
	  break;
	case OUTRES_ZONE:
	  cout << "Zone output requested:"<< endl;
	  break;
	case OUTRES_MIX:
	  cout << "Mixture output requested:"<< endl;
	  break;
	}

      /* list the reponses and features to come */
      /* units */
      outTypeNum = 0;
      cout << "\t" << Out_Types_Str[outTypeNum] << ": "
	   << ptr->actUnits << " " << ptr->normUnits << endl;
      /* regular singular responses */
      for (++outTypeNum;outTypeNum<lastSingularResponse;outTypeNum++)
	if (ptr->outTypes & 1<<outTypeNum)
	  {
	    switch(1<<outTypeNum)
	      {
	      case (OUTFMT_ACT):
		sprintf(buffer,Out_Types_Str[outTypeNum],
			ptr->actUnits,ptr->normUnits);
		break;
	      default:
		sprintf(buffer,Out_Types_Str[outTypeNum],
			ptr->normUnits);
	      }
	    cout << "\t" << buffer << endl;
	  }

      /* WDR header */
      if (ptr->outTypes & OUTFMT_WDR)
	for(filenameList::iterator fileName = ptr->wdrFilenames.begin();
	    fileName != ptr->wdrFilenames.end(); ++fileName)
	  cout << "\t" << Out_Types_Str[outTypeNum] << ": "
	       << *fileName << endl;

      cout << endl << endl;

      /* set units for activity */
      Result::setNorm(ptr->actMult, ptr->normMult);

      /* for each indicated response */
      for (outTypeNum=firstResponse;outTypeNum<lastSingularResponse;outTypeNum++)
	if (ptr->outTypes & 1<<outTypeNum)
	  {
	    /* write a response title */
	    switch(1<<outTypeNum)
	      {
	      case(OUTFMT_ACT):
		sprintf(buffer,Out_Types_Str[outTypeNum],
			ptr->actUnits,ptr->normUnits);
	      default:
		sprintf(buffer,Out_Types_Str[outTypeNum],ptr->normUnits);
	      }
	    cout << "*** " << buffer << " ***" << endl;

	    /* call write() on the appropriate object determined by
               the resulotition */
	    switch(ptr->resolution)
	      {
	      case OUTRES_INT:
		volList->write(1<<outTypeNum,ptr->outTypes & OUTFMT_COMP,
			       coolList,targetKza);
		break;
	      case OUTRES_ZONE:
		loadList->write(1<<outTypeNum,ptr->outTypes & OUTFMT_COMP,
				coolList,targetKza);
		break;
	      case OUTRES_MIX:
		mixList->write(1<<outTypeNum,ptr->outTypes & OUTFMT_COMP,
			       coolList,targetKza);
		break;
	      }

	    cout << endl << endl << endl;
	  }

      if (ptr->outTypes & OUTFMT_WDR)
	{
	  cout << "*** WDR ***" << endl;
	  for(filenameList::iterator fileName = ptr->wdrFilenames.begin();
	      fileName != ptr->wdrFilenames.end(); ++fileName)
	    {

	      /* write a response title */
	      cout << "*** " << Out_Types_Str[outTypeNum] << ": "
		   << *fileName << " ***" << endl;

	      Node::loadWDR(*fileName);

	      /* call write() on the appropriate object determined by
		 the resulotition */
	      switch(ptr->resolution)
		{
		case OUTRES_INT:
		  volList->write(OUTFMT_WDR,ptr->outTypes & OUTFMT_COMP,
				 coolList,targetKza);
		  break;
		case OUTRES_ZONE:
		  loadList->write(OUTFMT_WDR,ptr->outTypes & OUTFMT_COMP,
				  coolList,targetKza);
		  break;
		case OUTRES_MIX:
		  mixList->write(OUTFMT_WDR,ptr->outTypes & OUTFMT_COMP,
				 coolList,targetKza);
		  break;
		}

	      delete [] *fileName;
	      cout << endl << endl << endl;
	    }

	}
    }

}
<commit_msg>Rationalize support for normalization multiplier m3 as alternative to cm3. - make sure the correct conversion is used to be consistent with    implementation in Result.C<commit_after>/* $Id: OutputFormat.C,v 1.18 1999-11-09 17:17:52 wilson Exp $ */
#include "OutputFormat.h"

#include "Input/CoolingTime.h"
#include "Input/Volume.h"
#include "Input/Mixture.h"
#include "Input/Loading.h"

#include "Chains/Node.h"

#define Bq2Ci 2.7027e-11
#define cm32m3 1e-6

const char *Out_Types = "ucnstabgw";

const int nOutTypes = 9;
const int firstResponse = 2;
const int lastSingularResponse = 8;
const char *Out_Types_Str[nOutTypes] = {
  "Response Units",
  "Break-down by Component",
  "Number Density [atoms/%s]",
  "Specific Activity [%s/%s]",
  "Total Decay Heat [W/%s]",
  "Alpha Decay Heat [W/%s]",
  "Beta Decay Heat [W/%s]",
  "Gamma Decay Heat [W/%s]",
  "WDR/Clearance index"};

/***************************
 ********* Service *********
 **************************/

OutputFormat::OutputFormat(int type)
{
  resolution = type;
  outTypes = 0;
  actUnits = new char[3];
  strcpy(actUnits,"Bq");
  actMult = 1;

  normUnits = new char[4];
  strcpy(normUnits,"cm3");
  normMult = 1;

  next = NULL;
}

OutputFormat::OutputFormat(const OutputFormat& o) :
  resolution(o.resolution), outTypes(o.outTypes), actMult(o.actMult),
  normMult(o.normMult)
{
  actUnits = new char[strlen(o.actUnits)+1];
  strcpy(actUnits,o.actUnits);

  normUnits = new char[strlen(o.normUnits)+1];
  strcpy(normUnits,o.normUnits);

  next = NULL;
}

OutputFormat::~OutputFormat()
{
  delete actUnits;
  delete normUnits;
  delete next;
}

OutputFormat& OutputFormat::operator=(const OutputFormat& o)
{
  if (this == &o)
    return *this;

  resolution = o.resolution;
  outTypes = o.outTypes;
  delete actUnits;
  actUnits = new char[strlen(o.actUnits)+1];
  strcpy(actUnits,o.actUnits);
  actMult = o.actMult;

  delete normUnits;
  normUnits = new char[strlen(o.normUnits)+1];
  strcpy(normUnits,o.normUnits);
  normMult = o.normMult;

  return *this;
}

/***************************
 ********** Input **********
 **************************/

OutputFormat* OutputFormat::getOutFmts(istream& input)
{
  const char *Out_Res = " izm";

  int type;
  char token[64];
  char *fileNamePtr;

  input >> token;
  type = strchr(Out_Res,tolower(token[0]))-Out_Res;

  next = new OutputFormat(type);

  verbose(2,"Added output at resolution %d (%s)",type,token);

  /* read a list of output types until keyword "end" */
  clearComment(input);
  input >> token;
  while (strcmp(token,"end"))
    {
      /* match the first character of the type in the constant string */
      type = strchr(Out_Types,tolower(token[0]))-Out_Types;
      if (type<0)
	error(230,"Output type '%s' is not currently supported.",
	      token);

      /* use logical and to set the correct bit in the outTypes field */
      next->outTypes |= 1<<type;

      verbose(3,"Added output type %d (%s)",1<<type,token);

      switch (1<<type)
	{
	case OUTFMT_UNITS:
	  input >> token;
	  next->actUnits = new char[strlen(token)+1];
	  strcpy(next->actUnits,token);
	  next->actMult = (tolower(token[0]) == 'c'?Bq2Ci:1);

	  input >> token;
	  next->normUnits = new char[strlen(token)+1];
	  strcpy(next->normUnits,token);
	  next->normMult = (tolower(token[0]) == 'm'?cm32m3:1);
	  break;
	case OUTFMT_WDR:
	  input >> token;
	  fileNamePtr = new char[strlen(token)+1];
	  strcpy(fileNamePtr,token);
	  next->wdrFilenames.insert(fileNamePtr);
	  verbose(4,"Added WDR/Clearance file %s", token);
	}

      clearComment(input);
      input >> token;
    }

  return next;

}

void OutputFormat::write(Volume* volList, Mixture* mixList, Loading* loadList,
			 CoolingTime *coolList, int targetKza)
{

  OutputFormat *ptr = this;
  char buffer[64];

  int outTypeNum;

  /* for each output description */
  while (ptr->next != NULL)
    {

      ptr = ptr->next;

      /* write a header */
      switch(ptr->resolution)
	{
	case OUTRES_INT:
	  cout << "Interval output requested:"<< endl;
	  break;
	case OUTRES_ZONE:
	  cout << "Zone output requested:"<< endl;
	  break;
	case OUTRES_MIX:
	  cout << "Mixture output requested:"<< endl;
	  break;
	}

      /* list the reponses and features to come */
      /* units */
      outTypeNum = 0;
      cout << "\t" << Out_Types_Str[outTypeNum] << ": "
	   << ptr->actUnits << " " << ptr->normUnits << endl;
      /* regular singular responses */
      for (++outTypeNum;outTypeNum<lastSingularResponse;outTypeNum++)
	if (ptr->outTypes & 1<<outTypeNum)
	  {
	    switch(1<<outTypeNum)
	      {
	      case (OUTFMT_ACT):
		sprintf(buffer,Out_Types_Str[outTypeNum],
			ptr->actUnits,ptr->normUnits);
		break;
	      default:
		sprintf(buffer,Out_Types_Str[outTypeNum],
			ptr->normUnits);
	      }
	    cout << "\t" << buffer << endl;
	  }

      /* WDR header */
      if (ptr->outTypes & OUTFMT_WDR)
	for(filenameList::iterator fileName = ptr->wdrFilenames.begin();
	    fileName != ptr->wdrFilenames.end(); ++fileName)
	  cout << "\t" << Out_Types_Str[outTypeNum] << ": "
	       << *fileName << endl;

      cout << endl << endl;

      /* set units for activity */
      Result::setNorm(ptr->actMult, ptr->normMult);

      /* for each indicated response */
      for (outTypeNum=firstResponse;outTypeNum<lastSingularResponse;outTypeNum++)
	if (ptr->outTypes & 1<<outTypeNum)
	  {
	    /* write a response title */
	    switch(1<<outTypeNum)
	      {
	      case(OUTFMT_ACT):
		sprintf(buffer,Out_Types_Str[outTypeNum],
			ptr->actUnits,ptr->normUnits);
	      default:
		sprintf(buffer,Out_Types_Str[outTypeNum],ptr->normUnits);
	      }
	    cout << "*** " << buffer << " ***" << endl;

	    /* call write() on the appropriate object determined by
               the resulotition */
	    switch(ptr->resolution)
	      {
	      case OUTRES_INT:
		volList->write(1<<outTypeNum,ptr->outTypes & OUTFMT_COMP,
			       coolList,targetKza);
		break;
	      case OUTRES_ZONE:
		loadList->write(1<<outTypeNum,ptr->outTypes & OUTFMT_COMP,
				coolList,targetKza);
		break;
	      case OUTRES_MIX:
		mixList->write(1<<outTypeNum,ptr->outTypes & OUTFMT_COMP,
			       coolList,targetKza);
		break;
	      }

	    cout << endl << endl << endl;
	  }

      if (ptr->outTypes & OUTFMT_WDR)
	{
	  cout << "*** WDR ***" << endl;
	  for(filenameList::iterator fileName = ptr->wdrFilenames.begin();
	      fileName != ptr->wdrFilenames.end(); ++fileName)
	    {

	      /* write a response title */
	      cout << "*** " << Out_Types_Str[outTypeNum] << ": "
		   << *fileName << " ***" << endl;

	      Node::loadWDR(*fileName);

	      /* call write() on the appropriate object determined by
		 the resulotition */
	      switch(ptr->resolution)
		{
		case OUTRES_INT:
		  volList->write(OUTFMT_WDR,ptr->outTypes & OUTFMT_COMP,
				 coolList,targetKza);
		  break;
		case OUTRES_ZONE:
		  loadList->write(OUTFMT_WDR,ptr->outTypes & OUTFMT_COMP,
				  coolList,targetKza);
		  break;
		case OUTRES_MIX:
		  mixList->write(OUTFMT_WDR,ptr->outTypes & OUTFMT_COMP,
				 coolList,targetKza);
		  break;
		}

	      delete [] *fileName;
	      cout << endl << endl << endl;
	    }

	}
    }

}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile$

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
//This test demonstrates the use of sort last distributed memory parallel
//rendering with Piston.
//
//The pipeline is created in parallel and each process is
//assigned 1 piece to process. Each node then renders its local image and
//the image results are depth composited to produce a correct image on the
//root node.

#include <mpi.h>

#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCompositeRenderManager.h"
#include "vtkContourFilter.h"
#include "vtkDataSetToPiston.h"
#include "vtkImageMandelbrotSource.h"
#include "vtkLookupTable.h"
#include "vtkMPICommunicator.h"
#include "vtkMPIController.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkPieceScalars.h"
#include "vtkPistonContour.h"
#include "vtkPistonMapper.h"
#include "vtkPolyDataMapper.h"
#include "vtkProcess.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSphereSource.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkSynchronizedRenderWindows.h"
#include "vtkSynchronizedRenderers.h"
#include "vtkTestUtilities.h"

class MyProcess : public vtkProcess
{
public:
  static MyProcess *New();
  vtkTypeMacro(MyProcess, vtkProcess);

  virtual void Execute();

  void SetArgs(int argc, char *argv[])
    {
      this->Argc = argc;
      this->Argv = argv;
    }

  void CreatePipeline(vtkRenderer *renderer)
    {
    int num_procs = this->Controller->GetNumberOfProcesses();
    int my_id = this->Controller->GetLocalProcessId();

    vtkSmartPointer<vtkImageMandelbrotSource> src =
      vtkSmartPointer<vtkImageMandelbrotSource>::New();
    vtkSmartPointer<vtkDataSetToPiston> d2p =
      vtkSmartPointer<vtkDataSetToPiston>::New();
    vtkSmartPointer<vtkPistonContour> contour =
      vtkSmartPointer<vtkPistonContour>::New();
    vtkSmartPointer<vtkContourFilter> vtkcontour =
      vtkSmartPointer<vtkContourFilter>::New();

    vtkSmartPointer<vtkSphereSource> sphere =
      vtkSmartPointer<vtkSphereSource>::New();
    vtkSmartPointer<vtkPieceScalars> piecescalars =
      vtkSmartPointer<vtkPieceScalars>::New();
    vtkSmartPointer<vtkPistonMapper> mapper =
      vtkSmartPointer<vtkPistonMapper>::New();
    vtkSmartPointer<vtkPolyDataMapper> pdm =
      vtkSmartPointer<vtkPolyDataMapper>::New();
    vtkSmartPointer<vtkActor> actor =
      vtkSmartPointer<vtkActor>::New();

#define TESTPISTON 1
#define TESTUNSTRUCTURED 1

#if TESTPISTON
#if TESTUNSTRUCTURED
    sphere->SetPhiResolution(100);
    sphere->SetThetaResolution(100);
    piecescalars->SetInputConnection(sphere->GetOutputPort());
    piecescalars->SetScalarModeToCellData();
    d2p->SetInputConnection(piecescalars->GetOutputPort());

    mapper->SetInputConnection(d2p->GetOutputPort());
    mapper->SetPiece(my_id);
    mapper->SetNumberOfPieces(num_procs);

#else // TESTSTRUCTURED
    src->SetWholeExtent(0,40,0,40,0,40);
    d2p->SetInputConnection(src->GetOutputPort());
    contour->SetInputConnection(d2p->GetOutputPort());
    contour->SetIsoValue(50.0);

    mapper->SetInputConnection(contour->GetOutputPort());
    mapper->SetPiece(my_id);
    mapper->SetNumberOfPieces(num_procs);

#endif
    mapper->Update(); // TODO: shouldn't need this
    actor->SetMapper(mapper);
#else // TESTPISTON

#if TESTUNSTRUCTURED
    sphere->SetPhiResolution(100);
    sphere->SetThetaResolution(100);
    piecescalars->SetInputConnection(sphere->GetOutputPort());
    piecescalars->SetScalarModeToCellData();

    pdm->SetInputConnection(piecescalars->GetOutputPort());
    pdm->SetScalarModeToUseCellFieldData();
    pdm->SelectColorArray("Piece");
    pdm->SetScalarRange(0, num_procs-1);
    pdm->SetPiece(my_id);
    pdm->SetNumberOfPieces(num_procs);

#else // TESTSTRUCTURED
    src->SetWholeExtent(0,40,0,40,0,40);
    vtkcontour->SetInputConnection(src->GetOutputPort());
    vtkcontour->SetNumberOfContours(1);
    vtkcontour->SetValue(0, 50.0);

    pdm->SetInputConnection(vtkcontour->GetOutputPort());
    pdm->SetPiece(my_id);
    pdm->SetNumberOfPieces(num_procs);

#endif

    pdm->Update(); //TODO: Why is this needed?
    actor->SetMapper(pdm);
#endif

    renderer->AddActor(actor);
    }

protected:
  MyProcess() { this->Argc = 0; this->Argv = NULL; }

  int Argc;
  char **Argv;
};

//#vtkCxxRevisionMacro(MyProcess, "1.0");
vtkStandardNewMacro(MyProcess);

void MyProcess::Execute()
{
  int my_id = this->Controller->GetLocalProcessId();

  int go;
  vtkMPICommunicator *comm =
    vtkMPICommunicator::SafeDownCast(this->Controller->GetCommunicator());
  comm->Barrier();

  // TODO: Update to utkarsh's new architecture
  vtkSmartPointer<vtkCompositeRenderManager> prm =
    vtkSmartPointer<vtkCompositeRenderManager>::New();
  vtkRenderer *renderer = prm->MakeRenderer();
  vtkRenderWindow *renWin = prm->MakeRenderWindow();
  renWin->AddRenderer(renderer);
  renWin->DoubleBufferOn();
  renWin->Render();

  // TODO: Add an argument to decide if use interop or not
  vtkPistonMapper::InitCudaGL(renWin);

  this->CreatePipeline(renderer);
  prm->SetRenderWindow(renWin);
  prm->SetController(this->Controller);

  if (my_id == 0)
    {
    prm->ResetAllCameras();

    vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
    iren->SetRenderWindow(renWin);
    this->ReturnValue =
      vtkRegressionTester::Test(this->Argc, this->Argv, renWin, 10);

    if (this->ReturnValue == vtkRegressionTester::DO_INTERACTOR)
      {
      prm->StartInteractor();
      }

    iren->Delete();

    this->Controller->TriggerBreakRMIs();
    this->Controller->Barrier();
    }
  else
    {
    prm->StartServices();
    this->Controller->Barrier();

    // No testing is done here so mark it passed
    this->ReturnValue = vtkTesting::PASSED;
    }

  renderer->Delete();
  renWin->Delete();
}

int main(int argc, char **argv)
{
  // This is here to avoid false leak messages from vtkDebugLeaks when
  // using mpich. It appears that the root process which spawns all the
  // main processes waits in MPI_Init() and calls exit() when
  // the others are done, causing apparent memory leaks for any objects
  // created before MPI_Init().
  MPI_Init(&argc, &argv);

  // Note that this will create a vtkMPIController if MPI
  // is configured, vtkThreadedController otherwise.
  vtkMPIController *contr = vtkMPIController::New();
  contr->Initialize(&argc, &argv, 1);

  int retVal = 1; // 1 == failed

  int numProcs = contr->GetNumberOfProcesses();

  if (numProcs < 2 && false)
    {
    cout << "This test requires at least 2 processes" << endl;
    contr->Delete();
    return retVal;
    }

  vtkMultiProcessController::SetGlobalController(contr);

  MyProcess *p = MyProcess::New();
  p->SetArgs(argc, argv);

  contr->SetSingleProcessObject(p);
  contr->SingleMethodExecute();

  retVal = p->GetReturnValue();

  p->Delete();
  contr->Finalize();
  contr->Delete();
  vtkMultiProcessController::SetGlobalController(0);
  return !retVal;
}
<commit_msg>Fix parallel piston test on linux<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    $RCSfile$

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
//This test demonstrates the use of sort last distributed memory parallel
//rendering with Piston.
//
//The pipeline is created in parallel and each process is
//assigned 1 piece to process. Each node then renders its local image and
//the image results are depth composited to produce a correct image on the
//root node.

#include <mpi.h>

#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCompositeRenderManager.h"
#include "vtkContourFilter.h"
#include "vtkDataSetToPiston.h"
#include "vtkImageMandelbrotSource.h"
#include "vtkLookupTable.h"
#include "vtkMPICommunicator.h"
#include "vtkMPIController.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkPieceScalars.h"
#include "vtkPistonContour.h"
#include "vtkPistonMapper.h"
#include "vtkPolyDataMapper.h"
#include "vtkProcess.h"
#include "vtkRegressionTestImage.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSphereSource.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkSynchronizedRenderWindows.h"
#include "vtkSynchronizedRenderers.h"
#include "vtkTestUtilities.h"

class MyProcess : public vtkProcess
{
public:
  static MyProcess *New();
  vtkTypeMacro(MyProcess, vtkProcess);

  virtual void Execute();

  void SetArgs(int argc, char *argv[])
    {
      this->Argc = argc;
      this->Argv = argv;
    }

  void CreatePipeline(vtkRenderer *renderer)
    {
    int num_procs = this->Controller->GetNumberOfProcesses();
    int my_id = this->Controller->GetLocalProcessId();

    vtkSmartPointer<vtkImageMandelbrotSource> src =
      vtkSmartPointer<vtkImageMandelbrotSource>::New();
    vtkSmartPointer<vtkDataSetToPiston> d2p =
      vtkSmartPointer<vtkDataSetToPiston>::New();
    vtkSmartPointer<vtkPistonContour> contour =
      vtkSmartPointer<vtkPistonContour>::New();
    vtkSmartPointer<vtkContourFilter> vtkcontour =
      vtkSmartPointer<vtkContourFilter>::New();

    vtkSmartPointer<vtkSphereSource> sphere =
      vtkSmartPointer<vtkSphereSource>::New();
    vtkSmartPointer<vtkPieceScalars> piecescalars =
      vtkSmartPointer<vtkPieceScalars>::New();
    vtkSmartPointer<vtkPistonMapper> mapper =
      vtkSmartPointer<vtkPistonMapper>::New();
    vtkSmartPointer<vtkPolyDataMapper> pdm =
      vtkSmartPointer<vtkPolyDataMapper>::New();
    vtkSmartPointer<vtkActor> actor =
      vtkSmartPointer<vtkActor>::New();

#define TESTPISTON 1
#define TESTUNSTRUCTURED 1

#if TESTPISTON
#if TESTUNSTRUCTURED
    sphere->SetPhiResolution(100);
    sphere->SetThetaResolution(100);
    piecescalars->SetInputConnection(sphere->GetOutputPort());
    piecescalars->SetScalarModeToCellData();
    d2p->SetInputConnection(piecescalars->GetOutputPort());

    mapper->SetInputConnection(d2p->GetOutputPort());
    mapper->SetPiece(my_id);
    mapper->SetNumberOfPieces(num_procs);

#else // TESTSTRUCTURED
    src->SetWholeExtent(0,40,0,40,0,40);
    d2p->SetInputConnection(src->GetOutputPort());
    contour->SetInputConnection(d2p->GetOutputPort());
    contour->SetIsoValue(50.0);

    mapper->SetInputConnection(contour->GetOutputPort());
    mapper->SetPiece(my_id);
    mapper->SetNumberOfPieces(num_procs);

#endif
    mapper->Update(); // TODO: shouldn't need this
    actor->SetMapper(mapper);
#else // TESTPISTON

#if TESTUNSTRUCTURED
    sphere->SetPhiResolution(100);
    sphere->SetThetaResolution(100);
    piecescalars->SetInputConnection(sphere->GetOutputPort());
    piecescalars->SetScalarModeToCellData();

    pdm->SetInputConnection(piecescalars->GetOutputPort());
    pdm->SetScalarModeToUseCellFieldData();
    pdm->SelectColorArray("Piece");
    pdm->SetScalarRange(0, num_procs-1);
    pdm->SetPiece(my_id);
    pdm->SetNumberOfPieces(num_procs);

#else // TESTSTRUCTURED
    src->SetWholeExtent(0,40,0,40,0,40);
    vtkcontour->SetInputConnection(src->GetOutputPort());
    vtkcontour->SetNumberOfContours(1);
    vtkcontour->SetValue(0, 50.0);

    pdm->SetInputConnection(vtkcontour->GetOutputPort());
    pdm->SetPiece(my_id);
    pdm->SetNumberOfPieces(num_procs);

#endif

    pdm->Update(); //TODO: Why is this needed?
    actor->SetMapper(pdm);
#endif

    renderer->AddActor(actor);
    }

protected:
  MyProcess() { this->Argc = 0; this->Argv = NULL; }

  int Argc;
  char **Argv;
};

//#vtkCxxRevisionMacro(MyProcess, "1.0");
vtkStandardNewMacro(MyProcess);

void MyProcess::Execute()
{
  int my_id = this->Controller->GetLocalProcessId();

  int go;
  vtkMPICommunicator *comm =
    vtkMPICommunicator::SafeDownCast(this->Controller->GetCommunicator());
  comm->Barrier();

  // TODO: Update to utkarsh's new architecture
  vtkSmartPointer<vtkCompositeRenderManager> prm =
    vtkSmartPointer<vtkCompositeRenderManager>::New();
  vtkRenderer *renderer = prm->MakeRenderer();
  vtkRenderWindow *renWin = prm->MakeRenderWindow();
  renWin->AddRenderer(renderer);
  renWin->DoubleBufferOn();
  renWin->SetMultiSamples(0);
  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
  iren->SetRenderWindow(renWin);
  renWin->Render();

  // TODO: Add an argument to decide if use interop or not
  vtkPistonMapper::InitCudaGL(renWin);

  this->CreatePipeline(renderer);
  prm->SetRenderWindow(renWin);
  prm->SetController(this->Controller);

  if (my_id == 0)
    {
    prm->ResetAllCameras();

    this->ReturnValue =
      vtkRegressionTester::Test(this->Argc, this->Argv, renWin, 10);
    if (this->ReturnValue == vtkRegressionTester::DO_INTERACTOR)
      {
      renWin->Render();
      prm->StartInteractor();
      }

    this->Controller->TriggerBreakRMIs();
    this->Controller->Barrier();
    }
  else
    {
    prm->StartServices();
    this->Controller->Barrier();

    // No testing is done here so mark it passed
    this->ReturnValue = vtkTesting::PASSED;
    }

  renderer->Delete();
  renWin->Delete();
  iren->Delete();
}

int main(int argc, char **argv)
{
  // This is here to avoid false leak messages from vtkDebugLeaks when
  // using mpich. It appears that the root process which spawns all the
  // main processes waits in MPI_Init() and calls exit() when
  // the others are done, causing apparent memory leaks for any objects
  // created before MPI_Init().
  MPI_Init(&argc, &argv);

  // Note that this will create a vtkMPIController if MPI
  // is configured, vtkThreadedController otherwise.
  vtkMPIController *contr = vtkMPIController::New();
  contr->Initialize(&argc, &argv, 1);

  int retVal = 1; // 1 == failed

  int numProcs = contr->GetNumberOfProcesses();

  if (numProcs < 2 && false)
    {
    cout << "This test requires at least 2 processes" << endl;
    contr->Delete();
    return retVal;
    }

  vtkMultiProcessController::SetGlobalController(contr);

  MyProcess *p = MyProcess::New();
  p->SetArgs(argc, argv);

  contr->SetSingleProcessObject(p);
  contr->SingleMethodExecute();

  retVal = p->GetReturnValue();

  p->Delete();
  contr->Finalize();
  contr->Delete();
  vtkMultiProcessController::SetGlobalController(0);
  return !retVal;
}
<|endoftext|>