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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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 notices for more information.

=========================================================================*/

#include "mitkLevelWindowManager.h"
#include <itkCommand.h>
#include "mitkDataStorage.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkNodePredicateDataType.h"
#include "mitkNodePredicateAnd.h"
#include "mitkNodePredicateOr.h"
#include "mitkNodePredicateNot.h"
#include "mitkProperties.h"
#include "mitkMessage.h"

mitk::LevelWindowManager::LevelWindowManager()
: m_DataStorage(NULL), m_LevelWindowProperty(NULL), m_AutoTopMost(true),
  m_IsObserverTagSet(false), m_CurrentImage(NULL),m_IsPropertyModifiedTagSet(false)
{
}

mitk::LevelWindowManager::~LevelWindowManager()
{
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
    m_DataStorage = NULL;
  }
  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
}

void mitk::LevelWindowManager::SetDataStorage( mitk::DataStorage* ds )
{
  if (ds == NULL)
    return;

  /* remove listeners of old DataStorage */
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  }
  /* register listener for new DataStorage */
  m_DataStorage = ds;  // register
  m_DataStorage->AddNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
  m_DataStorage->RemoveNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  this->DataStorageChanged(); // update us with new DataStorage
}

void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject& )
{
  Modified();
}

void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode* removedNode)
{
  m_AutoTopMost = autoTopMost;
  if (m_AutoTopMost == false)
    return;

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  /* search topmost image */
  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }
  int maxLayer = itk::NumericTraits<int>::min();
  m_LevelWindowProperty = NULL;

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull() || (removedNode != NULL && node == removedNode))
      continue;
    if (node->IsVisible(NULL) == false)
      continue;
    int layer = 0;
    node->GetIntProperty("layer", layer);
    if ( layer < maxLayer )
      continue;
    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    maxLayer = layer;
  }
  Modified();
}

// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property.
// sets m_AutoTopMost to false
void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty)
{
  if (levelWindowProperty.IsNull())
    return;

  if (m_IsPropertyModifiedTagSet)  // remove listener for old property
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  m_LevelWindowProperty = levelWindowProperty;

  itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();  // register listener for new property
  command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified);
  m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver( itk::ModifiedEvent(), command );
  m_IsPropertyModifiedTagSet = true;
  m_AutoTopMost = false;

  /* search image than belongs to the property */
  mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
  mitk::DataNode* n = m_DataStorage->GetNode(p);
  if (n == NULL)
  {
    itkExceptionMacro("No Image in DataStorage that belongs to LevelWindow property " << m_LevelWindowProperty);
  }
  m_CurrentImage = dynamic_cast<mitk::Image*>(n->GetData());
  this->Modified();
}

// returns the current mitkLevelWindowProperty object from the image that is affected by changes
mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty()
{
  return m_LevelWindowProperty;
}

// returns Level/Window values for the current image
const mitk::LevelWindow& mitk::LevelWindowManager::GetLevelWindow()
{
  if (m_LevelWindowProperty.IsNotNull())
    return m_LevelWindowProperty->GetLevelWindow();
  else
  {
    itkExceptionMacro("No LevelWindow available!");
  }
}

// sets new Level/Window values and informs all listeners about changes
void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow& levelWindow)
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->SetLevelWindow(levelWindow);
  }
  this->Modified();
}

void mitk::LevelWindowManager::DataStorageChanged( const mitk::DataNode* )
{
  this->DataStorageRemovedNode();
}
void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::DataNode* removedNode )
{
  /* remove old observers */
  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode.clear();

  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode2.clear();

  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }

  /* listen to changes  in visible property of all images */

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in visible property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode[it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command )] = it->Value()->GetProperty("visible");
  }

  /* listen to changes  in layer property of all images */

  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in layer property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command2 = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command2->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode2[it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 )] = it->Value()->GetProperty("layer");
  }

  /* search image than belongs to the property */
  if (m_LevelWindowProperty.IsNull())
    SetAutoTopMostImage(true, removedNode);
  else
  {
    mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
    mitk::DataNode* n = m_DataStorage->GetNode(p2);
    if (n == NULL || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true change level window to topmost node
      SetAutoTopMostImage(true, removedNode);
   }
}

mitk::DataStorage* mitk::LevelWindowManager::GetDataStorage()
{
  return m_DataStorage.GetPointer();
}

// true if changes on slider or line-edits will affect always the topmost layer image
bool mitk::LevelWindowManager::isAutoTopMost()
{
  return m_AutoTopMost;
}

void mitk::LevelWindowManager::Update(const itk::EventObject&)  // visible property of a image has changed
{
  if (m_AutoTopMost)
  {
    SetAutoTopMostImage(true);
    return;
  }
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull())
      continue;
    if (node->IsVisible(NULL) == false)
      continue;
    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    if (m_LevelWindowProperty.IsNull() && m_LevelWindowProperty.GetPointer() == levelWindowProperty) // we found our m_LevelWindowProperty
    {
      return;
    }
  }
  Modified();
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes()
{
  if (m_DataStorage.IsNull())
    return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return empty set

  mitk::BoolProperty::Pointer trueProp = mitk::BoolProperty::New(true);
  mitk::NodePredicateProperty::Pointer notBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false));
  mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", NULL);

  mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image");
  mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage");
  mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage");
  mitk::NodePredicateDataType::Pointer isQImage = mitk::NodePredicateDataType::New("QBallImage");
  mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New();
  predicateTypes->AddPredicate(isImage);
  predicateTypes->AddPredicate(isDImage);
  predicateTypes->AddPredicate(isTImage);
  predicateTypes->AddPredicate(isQImage);

  mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New();
  predicate->AddPredicate(notBinary);
  predicate->AddPredicate(hasLevelWindow);
  predicate->AddPredicate(predicateTypes);

  mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset( predicate );
  return relevantNodes;
}

mitk::Image* mitk::LevelWindowManager::GetCurrentImage()
{
  return m_CurrentImage;
}
<commit_msg>setting property for levelWindow editing on correct node<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html 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 notices for more information.

=========================================================================*/

#include "mitkLevelWindowManager.h"
#include <itkCommand.h>
#include "mitkDataStorage.h"
#include "mitkNodePredicateBase.h"
#include "mitkNodePredicateProperty.h"
#include "mitkNodePredicateDataType.h"
#include "mitkNodePredicateAnd.h"
#include "mitkNodePredicateOr.h"
#include "mitkNodePredicateNot.h"
#include "mitkProperties.h"
#include "mitkMessage.h"

mitk::LevelWindowManager::LevelWindowManager()
: m_DataStorage(NULL), m_LevelWindowProperty(NULL), m_AutoTopMost(true),
  m_IsObserverTagSet(false), m_CurrentImage(NULL),m_IsPropertyModifiedTagSet(false)
{
}

mitk::LevelWindowManager::~LevelWindowManager()
{
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
    m_DataStorage = NULL;
  }
  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
  for( std::map<unsigned long, mitk::BaseProperty::Pointer>::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ ) {
    (*iter).second->RemoveObserver((*iter).first);
  }
}

void mitk::LevelWindowManager::SetDataStorage( mitk::DataStorage* ds )
{
  if (ds == NULL)
    return;

  /* remove listeners of old DataStorage */
  if (m_DataStorage.IsNotNull())
  {
    m_DataStorage->AddNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
    m_DataStorage->RemoveNodeEvent.RemoveListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  }
  /* register listener for new DataStorage */
  m_DataStorage = ds;  // register
  m_DataStorage->AddNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageChanged ));
  m_DataStorage->RemoveNodeEvent.AddListener(MessageDelegate1<LevelWindowManager, const mitk::DataNode*>( this, &LevelWindowManager::DataStorageRemovedNode ));
  this->DataStorageChanged(); // update us with new DataStorage
}

void mitk::LevelWindowManager::OnPropertyModified(const itk::EventObject& )
{
  Modified();
}

void mitk::LevelWindowManager::SetAutoTopMostImage(bool autoTopMost, const mitk::DataNode* removedNode)
{
  m_AutoTopMost = autoTopMost;
  if (m_AutoTopMost == false)
    return;

  if (m_IsPropertyModifiedTagSet && m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  /* search topmost image */
  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }
  int maxLayer = itk::NumericTraits<int>::min();
  m_LevelWindowProperty = NULL;

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull() || (removedNode != NULL && node == removedNode))
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    int layer = 0;
    node->GetIntProperty("layer", layer);
    if ( layer < maxLayer )
      continue;
    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    node->SetBoolProperty( "imageForLevelWindow", true );

    maxLayer = layer;
  }
  Modified();
}

// sets an specific LevelWindowProperty, all changes will affect the image belonging to this property.
// sets m_AutoTopMost to false
void mitk::LevelWindowManager::SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty)
{
  if (levelWindowProperty.IsNull())
    return;

  if (m_IsPropertyModifiedTagSet)  // remove listener for old property
  {
    m_LevelWindowProperty->RemoveObserver(m_PropertyModifiedTag);
    m_IsPropertyModifiedTagSet = false;
  }
  m_LevelWindowProperty = levelWindowProperty;

  itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();  // register listener for new property
  command->SetCallbackFunction(this, &LevelWindowManager::OnPropertyModified);
  m_PropertyModifiedTag = m_LevelWindowProperty->AddObserver( itk::ModifiedEvent(), command );
  m_IsPropertyModifiedTagSet = true;
  m_AutoTopMost = false;

  /* search image than belongs to the property */
  mitk::NodePredicateProperty::Pointer p = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
  mitk::DataNode* n = m_DataStorage->GetNode(p);
  if (n == NULL)
  {
    itkExceptionMacro("No Image in DataStorage that belongs to LevelWindow property " << m_LevelWindowProperty);
  }
  m_CurrentImage = dynamic_cast<mitk::Image*>(n->GetData());
  n->SetBoolProperty( "imageForLevelWindow", true );
  this->Modified();
}

// returns the current mitkLevelWindowProperty object from the image that is affected by changes
mitk::LevelWindowProperty::Pointer mitk::LevelWindowManager::GetLevelWindowProperty()
{
  return m_LevelWindowProperty;
}

// returns Level/Window values for the current image
const mitk::LevelWindow& mitk::LevelWindowManager::GetLevelWindow()
{
  if (m_LevelWindowProperty.IsNotNull())
    return m_LevelWindowProperty->GetLevelWindow();
  else
  {
    itkExceptionMacro("No LevelWindow available!");
  }
}

// sets new Level/Window values and informs all listeners about changes
void mitk::LevelWindowManager::SetLevelWindow(const mitk::LevelWindow& levelWindow)
{
  if (m_LevelWindowProperty.IsNotNull())
  {
    m_LevelWindowProperty->SetLevelWindow(levelWindow);
  }
  this->Modified();
}

void mitk::LevelWindowManager::DataStorageChanged( const mitk::DataNode* )
{
  this->DataStorageRemovedNode();
}
void mitk::LevelWindowManager::DataStorageRemovedNode( const mitk::DataNode* removedNode )
{
  /* remove old observers */
  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode.begin(); iter != m_PropObserverToNode.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode.clear();

  for (ObserverToPropertyMap::iterator iter = m_PropObserverToNode2.begin(); iter != m_PropObserverToNode2.end(); iter++ )
    (*iter).second->RemoveObserver((*iter).first);
  m_PropObserverToNode2.clear();

  if (m_DataStorage.IsNull())
  {
    itkExceptionMacro("DataStorage not set");
  }

  /* listen to changes  in visible property of all images */

  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in visible property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode[it->Value()->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command )] = it->Value()->GetProperty("visible");
  }

  /* listen to changes  in layer property of all images */

  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    if (it->Value().IsNull())
      continue;
    /* register listener for changes in layer property */
    itk::ReceptorMemberCommand<LevelWindowManager>::Pointer command2 = itk::ReceptorMemberCommand<LevelWindowManager>::New();
    command2->SetCallbackFunction(this, &LevelWindowManager::Update);
    m_PropObserverToNode2[it->Value()->GetProperty("layer")->AddObserver( itk::ModifiedEvent(), command2 )] = it->Value()->GetProperty("layer");
  }

  /* search image than belongs to the property */
  if (m_LevelWindowProperty.IsNull())
    SetAutoTopMostImage(true, removedNode);
  else
  {
    mitk::NodePredicateProperty::Pointer p2 = mitk::NodePredicateProperty::New("levelwindow", m_LevelWindowProperty);
    mitk::DataNode* n = m_DataStorage->GetNode(p2);
    if (n == NULL || m_AutoTopMost) // if node was deleted, change our behaviour to AutoTopMost, if AutoTopMost is true change level window to topmost node
      SetAutoTopMostImage(true, removedNode);
   }
}

mitk::DataStorage* mitk::LevelWindowManager::GetDataStorage()
{
  return m_DataStorage.GetPointer();
}

// true if changes on slider or line-edits will affect always the topmost layer image
bool mitk::LevelWindowManager::isAutoTopMost()
{
  return m_AutoTopMost;
}

void mitk::LevelWindowManager::Update(const itk::EventObject&)  // visible property of a image has changed
{
  if (m_AutoTopMost)
  {
    SetAutoTopMostImage(true);
    return;
  }
  mitk::DataStorage::SetOfObjects::ConstPointer all = this->GetRelevantNodes();
  for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it)
  {
    mitk::DataNode::Pointer node = it->Value();
    if (node.IsNull())
      continue;

    node->SetBoolProperty( "imageForLevelWindow", false );

    if (node->IsVisible(NULL) == false)
      continue;

    mitk::LevelWindowProperty::Pointer levelWindowProperty = dynamic_cast<mitk::LevelWindowProperty*>(node->GetProperty("levelwindow"));
    if (levelWindowProperty.IsNull())
      continue;
    m_LevelWindowProperty = levelWindowProperty;
    m_CurrentImage = dynamic_cast<mitk::Image*>(node->GetData());
    node->SetBoolProperty( "imageForLevelWindow", true );
    if (m_LevelWindowProperty.IsNull() && m_LevelWindowProperty.GetPointer() == levelWindowProperty) // we found our m_LevelWindowProperty
    {
      return;
    }
  }
  Modified();
}

mitk::DataStorage::SetOfObjects::ConstPointer mitk::LevelWindowManager::GetRelevantNodes()
{
  if (m_DataStorage.IsNull())
    return mitk::DataStorage::SetOfObjects::ConstPointer(mitk::DataStorage::SetOfObjects::New());  // return empty set

  mitk::BoolProperty::Pointer trueProp = mitk::BoolProperty::New(true);
  mitk::NodePredicateProperty::Pointer notBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(false));
  mitk::NodePredicateProperty::Pointer hasLevelWindow = mitk::NodePredicateProperty::New("levelwindow", NULL);

  mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image");
  mitk::NodePredicateDataType::Pointer isDImage = mitk::NodePredicateDataType::New("DiffusionImage");
  mitk::NodePredicateDataType::Pointer isTImage = mitk::NodePredicateDataType::New("TensorImage");
  mitk::NodePredicateDataType::Pointer isQImage = mitk::NodePredicateDataType::New("QBallImage");
  mitk::NodePredicateOr::Pointer predicateTypes = mitk::NodePredicateOr::New();
  predicateTypes->AddPredicate(isImage);
  predicateTypes->AddPredicate(isDImage);
  predicateTypes->AddPredicate(isTImage);
  predicateTypes->AddPredicate(isQImage);

  mitk::NodePredicateAnd::Pointer predicate = mitk::NodePredicateAnd::New();
  predicate->AddPredicate(notBinary);
  predicate->AddPredicate(hasLevelWindow);
  predicate->AddPredicate(predicateTypes);

  mitk::DataStorage::SetOfObjects::ConstPointer relevantNodes = m_DataStorage->GetSubset( predicate );
  return relevantNodes;
}

mitk::Image* mitk::LevelWindowManager::GetCurrentImage()
{
  return m_CurrentImage;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_VERTEX_HPP
#define MAPNIK_VERTEX_HPP

#include <sstream>

namespace mapnik
{

enum CommandType {
    SEG_END   =0,
    SEG_MOVETO=1,
    SEG_LINETO=2,
    SEG_CLOSE =3
};

template <typename T,int dim>
struct vertex {
    typedef T coord_type;
};

template <typename T>
struct vertex<T,2>
{
    enum no_init_t { no_init };

    typedef T coord_type;
    coord_type x;
    coord_type y;
    unsigned cmd;

    vertex()
        : x(0),y(0),cmd(SEG_END) {}

    explicit vertex(no_init_t)
        {}

    vertex(coord_type x,coord_type y,unsigned cmd)
        : x(x),y(y),cmd(cmd) {}

    template <typename T2>
    vertex(const vertex<T2,2>& rhs)
        : x(coord_type(rhs.x)),
          y(coord_type(rhs.y)),
          cmd(rhs.cmd) {}

    template <typename T2> vertex<T,2> operator=(const vertex<T2,2>& rhs)
    {
        if (&cmd != &rhs.cmd)
        {
            x = coord_type(rhs.x);
            y = coord_type(rhs.y);
            cmd = rhs.cmd;
        }
        return *this;
    }
};

typedef vertex<double,2> vertex2d;
typedef vertex<int,2> vertex2i;

template <class charT,class traits,class T,int dim>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const vertex<T,dim>& c);

template <class charT,class traits,class T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const vertex<T,2>& v)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    switch (v.cmd)
    {
        case SEG_END: s << "End "; break;
        case SEG_MOVETO: s << "MoveTo "; break;
        case SEG_LINETO: s << "LineTo "; break;
        case SEG_CLOSE: s << "Close "; break;
    }
    s << "(" << v.x << ", " << v.y << ")";
    return out << s.str();
}

template <class charT,class traits,class T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const vertex<T,3>& v)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    s<<"vertex3("<<v.x<<","<<v.y<<","<<v.z<<",cmd="<<v.cmd<<")";
    out << s.str();
    return out;
}

}

#endif // MAPNIK_VERTEX_HPP
<commit_msg>+ fix SEG_CLOSE value to be compatible with agg<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_VERTEX_HPP
#define MAPNIK_VERTEX_HPP

#include <sstream>

namespace mapnik
{

enum CommandType {
    SEG_END    = 0,
    SEG_MOVETO = 1,
    SEG_LINETO = 2,
    SEG_CLOSE = (0x40 | 0x0f)
};

template <typename T,int dim>
struct vertex {
    typedef T coord_type;
};

template <typename T>
struct vertex<T,2>
{
    enum no_init_t { no_init };

    typedef T coord_type;
    coord_type x;
    coord_type y;
    unsigned cmd;

    vertex()
        : x(0),y(0),cmd(SEG_END) {}

    explicit vertex(no_init_t)
        {}

    vertex(coord_type x,coord_type y,unsigned cmd)
        : x(x),y(y),cmd(cmd) {}

    template <typename T2>
    vertex(const vertex<T2,2>& rhs)
        : x(coord_type(rhs.x)),
          y(coord_type(rhs.y)),
          cmd(rhs.cmd) {}

    template <typename T2> vertex<T,2> operator=(const vertex<T2,2>& rhs)
    {
        if (&cmd != &rhs.cmd)
        {
            x = coord_type(rhs.x);
            y = coord_type(rhs.y);
            cmd = rhs.cmd;
        }
        return *this;
    }
};

typedef vertex<double,2> vertex2d;
typedef vertex<int,2> vertex2i;

template <class charT,class traits,class T,int dim>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const vertex<T,dim>& c);

template <class charT,class traits,class T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const vertex<T,2>& v)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    switch (v.cmd)
    {
        case SEG_END: s << "End "; break;
        case SEG_MOVETO: s << "MoveTo "; break;
        case SEG_LINETO: s << "LineTo "; break;
        case SEG_CLOSE: s << "Close "; break;
    }
    s << "(" << v.x << ", " << v.y << ")";
    return out << s.str();
}

template <class charT,class traits,class T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const vertex<T,3>& v)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    s<<"vertex3("<<v.x<<","<<v.y<<","<<v.z<<",cmd="<<v.cmd<<")";
    out << s.str();
    return out;
}

}

#endif // MAPNIK_VERTEX_HPP
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_legacy
/// Example of TTasks.
/// Create a hierarchy of objects derived from TTask in library Mytasks
/// Show the tasks in a browser.
/// To execute a Task, use the context context menu and select
/// the item "ExecuteTask"
/// see also other functions in the TTask context menu, such as
///  - setting a breakpoint in one or more tasks
///  - enabling/disabling one task, etc
///
/// \macro_code
///
/// \author Rene Brun

#ifndef __RUN_TASKS__

void tasks()
{
   TString dir = gSystem->UnixPathName(__FILE__);
   dir.ReplaceAll("tasks.C","");
   dir.ReplaceAll("/./","/");
   gROOT->LoadMacro(dir +"MyTasks.cxx+");

   gROOT->ProcessLine("#define __RUN_TASKS__ 1");
   gROOT->ProcessLine(TString("#include \"") + dir + "tasks.C\"");
   gROOT->ProcessLine("runtasks()");
   gROOT->ProcessLine("#undef __RUN_TASKS__");
}

#else

void runtasks()
//void tasks()
{
   TTask *run      = new MyRun("run","Process one run");
   TTask *event    = new MyEvent("event","Process one event");
   TTask *geomInit = new MyGeomInit("geomInit","Geometry Initialisation");
   TTask *matInit  = new MyMaterialInit("matInit","Materials Initialisation");
   TTask *tracker  = new MyTracker("tracker","Tracker manager");
   TTask *tpc      = new MyRecTPC("tpc","TPC Reconstruction");
   TTask *its      = new MyRecITS("its","ITS Reconstruction");
   TTask *muon     = new MyRecMUON("muon","MUON Reconstruction");
   TTask *phos     = new MyRecPHOS("phos","PHOS Reconstruction");
   TTask *rich     = new MyRecRICH("rich","RICH Reconstruction");
   TTask *trd      = new MyRecTRD("trd","TRD Reconstruction");
   TTask *global   = new MyRecGlobal("global","Global Reconstruction");

   run->Add(geomInit);
   run->Add(matInit);
   run->Add(event);
   event->Add(tracker);
   event->Add(global);
   tracker->Add(tpc);
   tracker->Add(its);
   tracker->Add(muon);
   tracker->Add(phos);
   tracker->Add(rich);
   tracker->Add(trd);

   gROOT->GetListOfTasks()->Add(run);
   gROOT->GetListOfBrowsables()->Add(run);
   new TBrowser;
}

#endif
<commit_msg>[tutorials] Explain why tasks.C is legacy (NFC).<commit_after>/// \file
/// \ingroup tutorial_legacy
/// Example of TTasks.
/// Create a hierarchy of objects derived from TTask in library Mytasks
/// Show the tasks in a browser.
/// To execute a Task, use the context context menu and select
/// the item "ExecuteTask"
/// see also other functions in the TTask context menu, such as
///  - setting a breakpoint in one or more tasks
///  - enabling/disabling one task, etc
///
/// As of 2021, tbb is a fine replacement for ROOT's task system. It
/// offers better interplay with non-ROOT multi-threading use cases.
///
/// \macro_code
///
/// \author Rene Brun

#ifndef __RUN_TASKS__

void tasks()
{
   TString dir = gSystem->UnixPathName(__FILE__);
   dir.ReplaceAll("tasks.C","");
   dir.ReplaceAll("/./","/");
   gROOT->LoadMacro(dir +"MyTasks.cxx+");

   gROOT->ProcessLine("#define __RUN_TASKS__ 1");
   gROOT->ProcessLine(TString("#include \"") + dir + "tasks.C\"");
   gROOT->ProcessLine("runtasks()");
   gROOT->ProcessLine("#undef __RUN_TASKS__");
}

#else

void runtasks()
//void tasks()
{
   TTask *run      = new MyRun("run","Process one run");
   TTask *event    = new MyEvent("event","Process one event");
   TTask *geomInit = new MyGeomInit("geomInit","Geometry Initialisation");
   TTask *matInit  = new MyMaterialInit("matInit","Materials Initialisation");
   TTask *tracker  = new MyTracker("tracker","Tracker manager");
   TTask *tpc      = new MyRecTPC("tpc","TPC Reconstruction");
   TTask *its      = new MyRecITS("its","ITS Reconstruction");
   TTask *muon     = new MyRecMUON("muon","MUON Reconstruction");
   TTask *phos     = new MyRecPHOS("phos","PHOS Reconstruction");
   TTask *rich     = new MyRecRICH("rich","RICH Reconstruction");
   TTask *trd      = new MyRecTRD("trd","TRD Reconstruction");
   TTask *global   = new MyRecGlobal("global","Global Reconstruction");

   run->Add(geomInit);
   run->Add(matInit);
   run->Add(event);
   event->Add(tracker);
   event->Add(global);
   tracker->Add(tpc);
   tracker->Add(its);
   tracker->Add(muon);
   tracker->Add(phos);
   tracker->Add(rich);
   tracker->Add(trd);

   gROOT->GetListOfTasks()->Add(run);
   gROOT->GetListOfBrowsables()->Add(run);
   new TBrowser;
}

#endif
<|endoftext|>


<commit_before>/*
 *
 * Area - Program that ask the user to enter the height and the width of
 *        triangle and print out the the area.
 *
 * Author - Moses Olawoyin <m.bastford@gmail.com
 * Date - 05 March 2015
 */

#include <iostream>

int main ( int argc, char *argv[])
{
    int width;
    int height;
    int area;

    std::cout <<"Enter the height" << std::endl;
    std::cin >> height;

    std::cout <<"Enter the width"<< std::endl;
    std::cin >> width;

    area = (height * width)/2;

    std::cout << "The area of the triangle is :"<< area << std::endl;

    return 0;
}
<commit_msg> created function for area calculation. closes #66<commit_after>/*
 *
 * Area - Program that ask the user to enter the height and the width of
 *        triangle and print out the the area.
 *
 * Author - Moses Olawoyin <m.bastford@gmail.com
 * Date - 05 March 2015
 */

#include <iostream>

int calc_area( int width, int height)
{
    return (width * height)/2;

}

int main ( int argc, char *argv[])
{
    int width;
    int height;
    int area;

    std::cout <<"Enter the height" << std::endl;
    std::cin >> height;

    std::cout <<"Enter the width"<< std::endl;
    std::cin >> width;

    area = calc_area(width, height);

    std::cout << "The area of the triangle is :"<< area << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <atomic>

namespace mos {
namespace gfx {

/** Base class for geometric shapes. */
class Shape {
public:
  Shape();
  /** Unique id. */
  unsigned int id() const;
private:
  static std::atomic_uint current_id_;
  unsigned int id_;
};

}
}

<commit_msg>Shape default constructor.<commit_after>#pragma once

#include <atomic>

namespace mos {
namespace gfx {

/** Base class for geometric shapes. */
class Shape {
public:
  Shape();
  ~Shape() = default;
  /** Unique id. */
  unsigned int id() const;
private:
  static std::atomic_uint current_id_;
  unsigned int id_;
};

}
}

<|endoftext|>


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

YASK: Yet Another Stencil Kernel
Copyright (c) 2014-2019, Intel Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

* The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

*****************************************************************************/

//////// Some common code shared between YASK compiler and kernel. //////////

// Include this first to assure NDEBUG is set properly.
#include "yask_assert.hpp"

#include <sstream>
#include "common_utils.hpp"

using namespace std;

namespace yask {

    // Update this version string anytime changes are
    // committed to a repository, especially when
    // affecting master or develop branches.
    // Be sure to keep 2 digits in minor and patch
    // fields to allow proper alphanumeric sorting
    // for numbers above 9 (at least up to 99).

    // Format: "major.minor.patch".
    const string version = "2.19.01";

    string yask_get_version_string() {
        return version;
    }

    // Controls whether make*Str() functions add
    // suffixes or just print full number for
    // machine parsing.
    bool is_suffix_print_enabled = true;

    // Return num with SI multiplier and "iB" suffix,
    // e.g., 412KiB.
    string makeByteStr(size_t nbytes)
    {
        if (!is_suffix_print_enabled)
            return to_string(nbytes);

        ostringstream os;
        double num = double(nbytes);
        const double oneK = 1024;
        const double oneM = oneK * oneK;
        const double oneG = oneK * oneM;
        const double oneT = oneK * oneG;
        const double oneP = oneK * oneT;
        const double oneE = oneK * oneP;
        if (num > oneE)
            os << (num / oneE) << "Ei";
        else if (num > oneP)
            os << (num / oneP) << "Pi";
        else if (num > oneT)
            os << (num / oneT) << "Ti";
        else if (num > oneG)
            os << (num / oneG) << "Gi";
        else if (num > oneM)
            os << (num / oneM) << "Mi";
        else if (num > oneK)
            os << (num / oneK) << "Ki";
        else
            os << num;
        os << "B";
        return os.str();
    }

    // Return num with SI multiplier, e.g. "3.14M".
    // Use this one for rates, etc.
    string makeNumStr(idx_t num) {
        if (!is_suffix_print_enabled || (num >= 0 && num < 1000))
            return to_string(num);
        return makeNumStr(double(num));
    }
    string makeNumStr(double num)
    {
        if (!is_suffix_print_enabled)
            return to_string(num);

        ostringstream os;
        const double oneK = 1e3;
        const double oneM = 1e6;
        const double oneG = 1e9;
        const double oneT = 1e12;
        const double oneP = 1e15;
        const double oneE = 1e18;
        const double onem = 1e-3;
        const double oneu = 1e-6;
        const double onen = 1e-9;
#ifdef USE_PICO
        const double onep = 1e-12;
        const double onef = 1e-15;
#endif
        if (num == 0.)
            os << num;
        else if (num > oneE)
            os << (num / oneE) << "E";
        else if (num > oneP)
            os << (num / oneP) << "P";
        else if (num > oneT)
            os << (num / oneT) << "T";
        else if (num > oneG)
            os << (num / oneG) << "G";
        else if (num > oneM)
            os << (num / oneM) << "M";
        else if (num > oneK)
            os << (num / oneK) << "K"; // NB: official SI symbol is "k".
#ifdef USE_PICO
        else if (num < onep)
            os << (num / onef) << "f";
        else if (num < onen)
            os << (num / onep) << "p";
#endif
        else if (num < oneu)
            os << (num / onen) << "n";
        else if (num < onem)
            os << (num / oneu) << "u"; // NB: official SI symbol is Greek mu.
        else if (num < 1.)
            os << (num / onem) << "m";
        else
            os << num;
        return os.str();
    }

    // A var that behaves like OMP_NUM_THREADS.
    int yask_num_threads[yask_max_levels] = { 0 };

    // See yask_common_api.hpp for documentation.
    const char* yask_exception::what() noexcept {
        return "yask::yask_exception\n";
    }

    void yask_exception::add_message(const string& arg_msg) {
        _msg.append(arg_msg);
    }

    const char* yask_exception::get_message() const {
        return _msg.c_str();
    }
}
<commit_msg>Update version.<commit_after>/*****************************************************************************

YASK: Yet Another Stencil Kernel
Copyright (c) 2014-2019, Intel Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

* The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

*****************************************************************************/

//////// Some common code shared between YASK compiler and kernel. //////////

// Include this first to assure NDEBUG is set properly.
#include "yask_assert.hpp"

#include <sstream>
#include "common_utils.hpp"

using namespace std;

namespace yask {

    // Update this version string anytime changes are
    // committed to a repository, especially when
    // affecting master or develop branches.
    // Be sure to keep 2 digits in minor and patch
    // fields to allow proper alphanumeric sorting
    // for numbers above 9 (at least up to 99).

    // Format: "major.minor.patch".
    const string version = "2.19.02";

    string yask_get_version_string() {
        return version;
    }

    // Controls whether make*Str() functions add
    // suffixes or just print full number for
    // machine parsing.
    bool is_suffix_print_enabled = true;

    // Return num with SI multiplier and "iB" suffix,
    // e.g., 412KiB.
    string makeByteStr(size_t nbytes)
    {
        if (!is_suffix_print_enabled)
            return to_string(nbytes);

        ostringstream os;
        double num = double(nbytes);
        const double oneK = 1024;
        const double oneM = oneK * oneK;
        const double oneG = oneK * oneM;
        const double oneT = oneK * oneG;
        const double oneP = oneK * oneT;
        const double oneE = oneK * oneP;
        if (num > oneE)
            os << (num / oneE) << "Ei";
        else if (num > oneP)
            os << (num / oneP) << "Pi";
        else if (num > oneT)
            os << (num / oneT) << "Ti";
        else if (num > oneG)
            os << (num / oneG) << "Gi";
        else if (num > oneM)
            os << (num / oneM) << "Mi";
        else if (num > oneK)
            os << (num / oneK) << "Ki";
        else
            os << num;
        os << "B";
        return os.str();
    }

    // Return num with SI multiplier, e.g. "3.14M".
    // Use this one for rates, etc.
    string makeNumStr(idx_t num) {
        if (!is_suffix_print_enabled || (num >= 0 && num < 1000))
            return to_string(num);
        return makeNumStr(double(num));
    }
    string makeNumStr(double num)
    {
        if (!is_suffix_print_enabled)
            return to_string(num);

        ostringstream os;
        const double oneK = 1e3;
        const double oneM = 1e6;
        const double oneG = 1e9;
        const double oneT = 1e12;
        const double oneP = 1e15;
        const double oneE = 1e18;
        const double onem = 1e-3;
        const double oneu = 1e-6;
        const double onen = 1e-9;
#ifdef USE_PICO
        const double onep = 1e-12;
        const double onef = 1e-15;
#endif
        if (num == 0.)
            os << num;
        else if (num > oneE)
            os << (num / oneE) << "E";
        else if (num > oneP)
            os << (num / oneP) << "P";
        else if (num > oneT)
            os << (num / oneT) << "T";
        else if (num > oneG)
            os << (num / oneG) << "G";
        else if (num > oneM)
            os << (num / oneM) << "M";
        else if (num > oneK)
            os << (num / oneK) << "K"; // NB: official SI symbol is "k".
#ifdef USE_PICO
        else if (num < onep)
            os << (num / onef) << "f";
        else if (num < onen)
            os << (num / onep) << "p";
#endif
        else if (num < oneu)
            os << (num / onen) << "n";
        else if (num < onem)
            os << (num / oneu) << "u"; // NB: official SI symbol is Greek mu.
        else if (num < 1.)
            os << (num / onem) << "m";
        else
            os << num;
        return os.str();
    }

    // A var that behaves like OMP_NUM_THREADS.
    int yask_num_threads[yask_max_levels] = { 0 };

    // See yask_common_api.hpp for documentation.
    const char* yask_exception::what() noexcept {
        return "yask::yask_exception\n";
    }

    void yask_exception::add_message(const string& arg_msg) {
        _msg.append(arg_msg);
    }

    const char* yask_exception::get_message() const {
        return _msg.c_str();
    }
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2019 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "geometry.h"
#include "scene.h"

namespace embree
{
  const char* Geometry::gtype_names[Geometry::GTY_END] =
  {
    "flat_linear_curve",
    "round_linear_curve",
    "oriented_linear_curve",
    "",
    "flat_bezier_curve",
    "round_bezier_curve",
    "oriented_bezier_curve",
    "",
    "flat_bspline_curve",
    "round_bspline_curve",
    "oriented_bspline_curve",
    "",
    "flat_hermite_curve",
    "round_hermite_curve",
    "oriented_hermite_curve",
    "",
    "flat_catmull_rom_curve",
    "round_catmull_rom_curve",
    "oriented_catmull_rom_curve",
    "",
    "triangles",
    "quads",
    "grid",
    "subdivs",
    "",
    "sphere",
    "disc",
    "oriented_disc",
    "",
    "usergeom",
    "instance_cheap",
    "instance_expensive",
  };

  Geometry::Geometry (Device* device, GType gtype, unsigned int numPrimitives, unsigned int numTimeSteps)
    : device(device), scene(nullptr), userPtr(nullptr),
      geomID(0), numPrimitives(numPrimitives), numTimeSteps(unsigned(numTimeSteps)), fnumTimeSegments(float(numTimeSteps-1)), time_range(0.0f,1.0f),
      mask(-1),
      gtype(gtype),
      quality(RTC_BUILD_QUALITY_MEDIUM),
      state(MODIFIED),
      numPrimitivesChanged(false),
      enabled(true),
      intersectionFilterN(nullptr), occlusionFilterN(nullptr), pointQueryFunc(nullptr)
  {
    device->refInc();
  }

  Geometry::~Geometry()
  {
    device->refDec();
  }

  void Geometry::setNumPrimitives(unsigned int numPrimitives_in)
  {
    if (numPrimitives_in == numPrimitives) return;

    numPrimitives = numPrimitives_in;
    numPrimitivesChanged = true;

    Geometry::update();
  }

  void Geometry::setNumTimeSteps (unsigned int numTimeSteps_in)
  {
    if (numTimeSteps_in == numTimeSteps)
      return;

    numTimeSteps = numTimeSteps_in;
    fnumTimeSegments = float(numTimeSteps_in-1);

    Geometry::update();
  }

  void Geometry::setTimeRange (const BBox1f range)
  {
    time_range = range;
    Geometry::update();
  }

  void Geometry::update()
  {
    if (scene)
      scene->setModified();

    state = MODIFIED;
  }

  void Geometry::commit()
  {
    if (scene)
      scene->setModified();

    state = COMMITTED;
  }

  void Geometry::preCommit()
  {
    if (state == MODIFIED)
      throw_RTCError(RTC_ERROR_INVALID_OPERATION,"geometry not committed");
  }

  void Geometry::postCommit()
  {
    numPrimitivesChanged = false;

    /* set state to build */
    if (isEnabled())
      state = BUILD;
  }

  void Geometry::updateIntersectionFilters(bool enable)
  {
    const size_t numN  = (intersectionFilterN  != nullptr) + (occlusionFilterN  != nullptr);

    if (enable) {
      scene->numIntersectionFiltersN += numN;
    } else {
      scene->numIntersectionFiltersN -= numN;
    }
  }

  Geometry* Geometry::attach(Scene* scene, unsigned int geomID)
  {
    assert(scene);
    this->scene = scene;
    this->geomID = geomID;
    if (isEnabled()) {
      scene->setModified();
      updateIntersectionFilters(true);
    }
    return this;
  }

  void Geometry::detach()
  {
    if (scene && isEnabled()) {
      scene->setModified();
      updateIntersectionFilters(false);
    }
    this->scene = nullptr;
    this->geomID = -1;
  }

  void Geometry::enable ()
  {
    if (isEnabled())
      return;

    if (scene) {
      updateIntersectionFilters(true);
      scene->setModified();
    }

    enabled = true;
  }

  void Geometry::disable ()
  {
    if (isDisabled())
      return;

    if (scene) {
      updateIntersectionFilters(false);
      scene->setModified();
    }

    enabled = false;
  }

  void Geometry::setUserData (void* ptr)
  {
    userPtr = ptr;
  }

  void Geometry::setIntersectionFilterFunctionN (RTCFilterFunctionN filter)
  {
    if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
      throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");

    if (scene && isEnabled()) {
      scene->numIntersectionFiltersN -= intersectionFilterN != nullptr;
      scene->numIntersectionFiltersN += filter != nullptr;
    }
    intersectionFilterN = filter;
  }

  void Geometry::setOcclusionFilterFunctionN (RTCFilterFunctionN filter)
  {
    if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
      throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");

    if (scene && isEnabled()) {
      scene->numIntersectionFiltersN -= occlusionFilterN != nullptr;
      scene->numIntersectionFiltersN += filter != nullptr;
    }
    occlusionFilterN = filter;
  }

  void Geometry::setPointQueryFunction (RTCPointQueryFunction func)
  {
    pointQueryFunc = func;
  }

  void Geometry::interpolateN(const RTCInterpolateNArguments* const args)
  {
    const void* valid_i = args->valid;
    const unsigned* primIDs = args->primIDs;
    const float* u = args->u;
    const float* v = args->v;
    unsigned int N = args->N;
    RTCBufferType bufferType = args->bufferType;
    unsigned int bufferSlot = args->bufferSlot;
    float* P = args->P;
    float* dPdu = args->dPdu;
    float* dPdv = args->dPdv;
    float* ddPdudu = args->ddPdudu;
    float* ddPdvdv = args->ddPdvdv;
    float* ddPdudv = args->ddPdudv;
    unsigned int valueCount = args->valueCount;

    if (valueCount > 256) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"maximally 256 floating point values can be interpolated per vertex");
    const int* valid = (const int*) valid_i;

    __aligned(64) float P_tmp[256];
    __aligned(64) float dPdu_tmp[256];
    __aligned(64) float dPdv_tmp[256];
    __aligned(64) float ddPdudu_tmp[256];
    __aligned(64) float ddPdvdv_tmp[256];
    __aligned(64) float ddPdudv_tmp[256];

    float* Pt = P ? P_tmp : nullptr;
    float* dPdut = nullptr, *dPdvt = nullptr;
    if (dPdu) { dPdut = dPdu_tmp; dPdvt = dPdv_tmp; }
    float* ddPdudut = nullptr, *ddPdvdvt = nullptr, *ddPdudvt = nullptr;
    if (ddPdudu) { ddPdudut = ddPdudu_tmp; ddPdvdvt = ddPdvdv_tmp; ddPdudvt = ddPdudv_tmp; }

    for (unsigned int i=0; i<N; i++)
    {
      if (valid && !valid[i]) continue;

      RTCInterpolateArguments iargs;
      iargs.primID = primIDs[i];
      iargs.u = u[i];
      iargs.v = v[i];
      iargs.bufferType = bufferType;
      iargs.bufferSlot = bufferSlot;
      iargs.P = Pt;
      iargs.dPdu = dPdut;
      iargs.dPdv = dPdvt;
      iargs.ddPdudu = ddPdudut;
      iargs.ddPdvdv = ddPdvdvt;
      iargs.ddPdudv = ddPdudvt;
      iargs.valueCount = valueCount;
      interpolate(&iargs);

      if (likely(P)) {
        for (unsigned int j=0; j<valueCount; j++)
          P[j*N+i] = Pt[j];
      }
      if (likely(dPdu))
      {
        for (unsigned int j=0; j<valueCount; j++) {
          dPdu[j*N+i] = dPdut[j];
          dPdv[j*N+i] = dPdvt[j];
        }
      }
      if (likely(ddPdudu))
      {
        for (unsigned int j=0; j<valueCount; j++) {
          ddPdudu[j*N+i] = ddPdudut[j];
          ddPdvdv[j*N+i] = ddPdvdvt[j];
          ddPdudv[j*N+i] = ddPdudvt[j];
        }
      }
    }
  }

  bool Geometry::pointQuery(PointQuery* query, PointQueryContext* context)
  {
    assert(context->primID < size());

    RTCPointQueryFunctionArguments args;
    args.query           = (RTCPointQuery*)context->query_ws;
    args.userPtr         = context->userPtr;
    args.primID          = context->primID;
    args.geomID          = context->geomID;
    args.context         = context->userContext;
    args.similarityScale = context->similarityScale;

    bool update = false;
    if(context->func)  update |= context->func(&args);
    if(pointQueryFunc) update |= pointQueryFunc(&args);

    if (update && context->userContext->instStackSize > 0)
    {
      // update point query
      if (context->query_type == POINT_QUERY_TYPE_AABB) {
        context->updateAABB();
      } else {
        assert(context->similarityScale > 0.f);
        query->radius = context->query_ws->radius * context->similarityScale;
      }
    }
    return update;
  }
}
<commit_msg>Detach geometries in Geometry::attach() if they are still attached to another scene.<commit_after>// ======================================================================== //
// Copyright 2009-2019 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "geometry.h"
#include "scene.h"

namespace embree
{
  const char* Geometry::gtype_names[Geometry::GTY_END] =
  {
    "flat_linear_curve",
    "round_linear_curve",
    "oriented_linear_curve",
    "",
    "flat_bezier_curve",
    "round_bezier_curve",
    "oriented_bezier_curve",
    "",
    "flat_bspline_curve",
    "round_bspline_curve",
    "oriented_bspline_curve",
    "",
    "flat_hermite_curve",
    "round_hermite_curve",
    "oriented_hermite_curve",
    "",
    "flat_catmull_rom_curve",
    "round_catmull_rom_curve",
    "oriented_catmull_rom_curve",
    "",
    "triangles",
    "quads",
    "grid",
    "subdivs",
    "",
    "sphere",
    "disc",
    "oriented_disc",
    "",
    "usergeom",
    "instance_cheap",
    "instance_expensive",
  };

  Geometry::Geometry (Device* device, GType gtype, unsigned int numPrimitives, unsigned int numTimeSteps)
    : device(device), scene(nullptr), userPtr(nullptr),
      geomID(0), numPrimitives(numPrimitives), numTimeSteps(unsigned(numTimeSteps)), fnumTimeSegments(float(numTimeSteps-1)), time_range(0.0f,1.0f),
      mask(-1),
      gtype(gtype),
      quality(RTC_BUILD_QUALITY_MEDIUM),
      state(MODIFIED),
      numPrimitivesChanged(false),
      enabled(true),
      intersectionFilterN(nullptr), occlusionFilterN(nullptr), pointQueryFunc(nullptr)
  {
    device->refInc();
  }

  Geometry::~Geometry()
  {
    device->refDec();
  }

  void Geometry::setNumPrimitives(unsigned int numPrimitives_in)
  {
    if (numPrimitives_in == numPrimitives) return;

    numPrimitives = numPrimitives_in;
    numPrimitivesChanged = true;

    Geometry::update();
  }

  void Geometry::setNumTimeSteps (unsigned int numTimeSteps_in)
  {
    if (numTimeSteps_in == numTimeSteps)
      return;

    numTimeSteps = numTimeSteps_in;
    fnumTimeSegments = float(numTimeSteps_in-1);

    Geometry::update();
  }

  void Geometry::setTimeRange (const BBox1f range)
  {
    time_range = range;
    Geometry::update();
  }

  void Geometry::update()
  {
    if (scene)
      scene->setModified();

    state = MODIFIED;
  }

  void Geometry::commit()
  {
    if (scene)
      scene->setModified();

    state = COMMITTED;
  }

  void Geometry::preCommit()
  {
    if (state == MODIFIED)
      throw_RTCError(RTC_ERROR_INVALID_OPERATION,"geometry not committed");
  }

  void Geometry::postCommit()
  {
    numPrimitivesChanged = false;

    /* set state to build */
    if (isEnabled())
      state = BUILD;
  }

  void Geometry::updateIntersectionFilters(bool enable)
  {
    const size_t numN  = (intersectionFilterN  != nullptr) + (occlusionFilterN  != nullptr);

    if (enable) {
      scene->numIntersectionFiltersN += numN;
    } else {
      scene->numIntersectionFiltersN -= numN;
    }
  }

  Geometry* Geometry::attach(Scene* scene, unsigned int geomID)
  {
    assert(scene);
    if (this->scene)
      this->scene->detachGeometry(this->geomID);

    this->scene = scene;
    this->geomID = geomID;
    if (isEnabled()) {
      scene->setModified();
      updateIntersectionFilters(true);
    }
    return this;
  }

  void Geometry::detach()
  {
    if (scene && isEnabled()) {
      scene->setModified();
      updateIntersectionFilters(false);
    }
    this->scene = nullptr;
    this->geomID = -1;
  }

  void Geometry::enable ()
  {
    if (isEnabled())
      return;

    if (scene) {
      updateIntersectionFilters(true);
      scene->setModified();
    }

    enabled = true;
  }

  void Geometry::disable ()
  {
    if (isDisabled())
      return;

    if (scene) {
      updateIntersectionFilters(false);
      scene->setModified();
    }

    enabled = false;
  }

  void Geometry::setUserData (void* ptr)
  {
    userPtr = ptr;
  }

  void Geometry::setIntersectionFilterFunctionN (RTCFilterFunctionN filter)
  {
    if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
      throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");

    if (scene && isEnabled()) {
      scene->numIntersectionFiltersN -= intersectionFilterN != nullptr;
      scene->numIntersectionFiltersN += filter != nullptr;
    }
    intersectionFilterN = filter;
  }

  void Geometry::setOcclusionFilterFunctionN (RTCFilterFunctionN filter)
  {
    if (!(getTypeMask() & (MTY_TRIANGLE_MESH | MTY_QUAD_MESH | MTY_CURVES | MTY_SUBDIV_MESH | MTY_USER_GEOMETRY | MTY_GRID_MESH)))
      throw_RTCError(RTC_ERROR_INVALID_OPERATION,"filter functions not supported for this geometry");

    if (scene && isEnabled()) {
      scene->numIntersectionFiltersN -= occlusionFilterN != nullptr;
      scene->numIntersectionFiltersN += filter != nullptr;
    }
    occlusionFilterN = filter;
  }

  void Geometry::setPointQueryFunction (RTCPointQueryFunction func)
  {
    pointQueryFunc = func;
  }

  void Geometry::interpolateN(const RTCInterpolateNArguments* const args)
  {
    const void* valid_i = args->valid;
    const unsigned* primIDs = args->primIDs;
    const float* u = args->u;
    const float* v = args->v;
    unsigned int N = args->N;
    RTCBufferType bufferType = args->bufferType;
    unsigned int bufferSlot = args->bufferSlot;
    float* P = args->P;
    float* dPdu = args->dPdu;
    float* dPdv = args->dPdv;
    float* ddPdudu = args->ddPdudu;
    float* ddPdvdv = args->ddPdvdv;
    float* ddPdudv = args->ddPdudv;
    unsigned int valueCount = args->valueCount;

    if (valueCount > 256) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"maximally 256 floating point values can be interpolated per vertex");
    const int* valid = (const int*) valid_i;

    __aligned(64) float P_tmp[256];
    __aligned(64) float dPdu_tmp[256];
    __aligned(64) float dPdv_tmp[256];
    __aligned(64) float ddPdudu_tmp[256];
    __aligned(64) float ddPdvdv_tmp[256];
    __aligned(64) float ddPdudv_tmp[256];

    float* Pt = P ? P_tmp : nullptr;
    float* dPdut = nullptr, *dPdvt = nullptr;
    if (dPdu) { dPdut = dPdu_tmp; dPdvt = dPdv_tmp; }
    float* ddPdudut = nullptr, *ddPdvdvt = nullptr, *ddPdudvt = nullptr;
    if (ddPdudu) { ddPdudut = ddPdudu_tmp; ddPdvdvt = ddPdvdv_tmp; ddPdudvt = ddPdudv_tmp; }

    for (unsigned int i=0; i<N; i++)
    {
      if (valid && !valid[i]) continue;

      RTCInterpolateArguments iargs;
      iargs.primID = primIDs[i];
      iargs.u = u[i];
      iargs.v = v[i];
      iargs.bufferType = bufferType;
      iargs.bufferSlot = bufferSlot;
      iargs.P = Pt;
      iargs.dPdu = dPdut;
      iargs.dPdv = dPdvt;
      iargs.ddPdudu = ddPdudut;
      iargs.ddPdvdv = ddPdvdvt;
      iargs.ddPdudv = ddPdudvt;
      iargs.valueCount = valueCount;
      interpolate(&iargs);

      if (likely(P)) {
        for (unsigned int j=0; j<valueCount; j++)
          P[j*N+i] = Pt[j];
      }
      if (likely(dPdu))
      {
        for (unsigned int j=0; j<valueCount; j++) {
          dPdu[j*N+i] = dPdut[j];
          dPdv[j*N+i] = dPdvt[j];
        }
      }
      if (likely(ddPdudu))
      {
        for (unsigned int j=0; j<valueCount; j++) {
          ddPdudu[j*N+i] = ddPdudut[j];
          ddPdvdv[j*N+i] = ddPdvdvt[j];
          ddPdudv[j*N+i] = ddPdudvt[j];
        }
      }
    }
  }

  bool Geometry::pointQuery(PointQuery* query, PointQueryContext* context)
  {
    assert(context->primID < size());

    RTCPointQueryFunctionArguments args;
    args.query           = (RTCPointQuery*)context->query_ws;
    args.userPtr         = context->userPtr;
    args.primID          = context->primID;
    args.geomID          = context->geomID;
    args.context         = context->userContext;
    args.similarityScale = context->similarityScale;

    bool update = false;
    if(context->func)  update |= context->func(&args);
    if(pointQueryFunc) update |= pointQueryFunc(&args);

    if (update && context->userContext->instStackSize > 0)
    {
      // update point query
      if (context->query_type == POINT_QUERY_TYPE_AABB) {
        context->updateAABB();
      } else {
        assert(context->similarityScale > 0.f);
        query->radius = context->query_ws->radius * context->similarityScale;
      }
    }
    return update;
  }
}
<|endoftext|>


<commit_before>/*
* 2013+ Copyright (c) Andrey Kashin <kashin.andrej@gmail.com>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*/

#ifndef UPDATER_HPP
#define UPDATER_HPP

#include <stack>
#include <stdexcept>

namespace react {

/*!
 * \brief Class for interactive building of call tree
 *
 *  Allows you to log actions in call-tree manner.
 */
template<typename TreeType>
class call_tree_updater_t {
public:
	typedef TreeType time_stats_tree_t;
	typedef concurrent_call_tree_t<TreeType> concurrent_time_stats_tree_t;

	/*!
	 * \brief Call tree node type
	 */
	typedef typename time_stats_tree_t::node_t node_t;

	/*!
	 * \brief Pointer to call tree node type
	 */
	typedef typename time_stats_tree_t::p_node_t p_node_t;

	/*!
	 * \brief Time point type
	 */
	typedef std::chrono::time_point<std::chrono::system_clock> time_point_t;

	/*!
	 * \brief Initializes updater without target tree
	 * \param max_depth Maximum monitored depth of call stack
	 */
	call_tree_updater_t(const size_t max_depth = DEFAULT_DEPTH):
		current_node(0), time_stats_tree(NULL), depth(0), max_depth(max_depth) {
		measurements.emplace(std::chrono::system_clock::now(), +time_stats_tree_t::NO_NODE);
	}

	/*!
	 * \brief Initializes updater with target tree
	 * \param time_stats_tree Tree used to monitor updates
	 * \param max_depth Maximum monitored depth of call stack
	 */
	call_tree_updater_t(concurrent_time_stats_tree_t &time_stats_tree,
						 const size_t max_depth = DEFAULT_DEPTH): call_tree_updater_t(max_depth) {
		set_time_stats_tree(time_stats_tree);
		measurements.emplace(std::chrono::system_clock::now(), +time_stats_tree_t::NO_NODE);
	}

	/*!
	 * \brief Checks if all actions were correctly finished.
	 */
	virtual ~call_tree_updater_t() {
		check_for_extra_measurements();
	}

	/*!
	 * \brief Sets target tree for updates
	 * \param time_stats_tree Tree used to monitor updates
	 */
	void set_time_stats_tree(concurrent_time_stats_tree_t &time_stats_tree) {
		check_for_extra_measurements();
		current_node = time_stats_tree.get_time_stats_tree().root;
		this->time_stats_tree = &time_stats_tree;
		depth = 0;
	}

	/*!
	 * \brief Resets current call tree
	 */
	void reset_time_stats_tree() {
		check_for_extra_measurements();
		current_node = time_stats_tree_t::NO_NODE;
		this->time_stats_tree = NULL;
		depth = 0;
	}

	/*!
	 * \brief Checks whether tree for updates is set
	 * \return whether updater target tree was set
	 */
	bool has_time_stats_tree() const {
		return (time_stats_tree != NULL);
	}

	/*!
	 * \brief Starts new branch in tree with action \a action_code
	 * \param action_code Code of new action
	 */
	virtual void start(const int action_code) {
		start(action_code, std::chrono::system_clock::now());
	}

	/*!
	 * \brief Starts new branch in tree with action \a action_code and with specified start time
	 * \param action_code Code of new action
	 * \param start_time Action start time
	 */
	void start(const int action_code, const time_point_t& start_time) {
		++depth;
		if (get_depth() > max_depth) {
			return;
		}

		time_stats_tree->lock();
		p_node_t next_node = time_stats_tree->get_time_stats_tree().add_new_link_if_missing(current_node, action_code);
		time_stats_tree->unlock();

		measurements.emplace(start_time, current_node);
		current_node = next_node;
	}

	/*!
	 * \brief Stops last action. Updates total consumed time in call-tree.
	 * \param action_code Code of finished action
	 */
	virtual void stop(const int action_code) {
		if (get_depth() > max_depth) {
			--depth;
			return;
		}

		std::lock_guard<concurrent_time_stats_tree_t> guard(*time_stats_tree);

		int expected_code = time_stats_tree->get_time_stats_tree().get_node_action_code(current_node);
		if (expected_code != action_code) {
			std::string expected_action_name = get_action_name(expected_code);
			std::string found_action_name = get_action_name(action_code);
			throw std::logic_error("Stopping wrong action. Expected: " + expected_action_name + ", Found: " + found_action_name);
		}
		pop_measurement();
	}

	/*!
	 * \brief Sets max monitored call stack depth to \a max_depth
	 * \param max_depth Max monitored call stack depth
	 */
	void set_max_depth(const size_t max_depth) {
		if (depth != 0) {
			throw std::logic_error("can't change max_depth during update");
		}

		this->max_depth = max_depth;
	}

	/*!
	 * \brief Gets current call stack depth
	 * \return Current call stack depth
	 */
	size_t get_depth() const {
		return depth;
	}

	/*!
	 * \brief Returns name of action with \a action_code
	 * \return Name of action with \a action_code
	 */
	std::string get_action_name(int action_code) const {
		return time_stats_tree->get_time_stats_tree().get_actions_set().get_action_name(action_code);
	}

	/*!
	 * \brief Returns name of action in current node
	 * \return Current's node action name
	 */
	std::string get_current_node_action_name() const {
		return get_action_name(time_stats_tree->get_time_stats_tree().get_node_action_code(current_node));
	}

private:
	/*!
	 * \internal
	 *
	 * \brief Returns delta between two time_points
	 */
	template<class Period = std::chrono::microseconds>
	long long int delta(time_point_t& start, const time_point_t& end) const {
		return (std::chrono::duration_cast<Period> (end - start)).count();
	}

	/*!
	 * \internal
	 *
	 * \brief Assures that updater is empty
	 */
	void check_for_extra_measurements() {
		if (depth != 0) {
			std::string error_message;
			if (!time_stats_tree) {
				error_message = "~time_stats_updater(): extra measurements, tree is NULL\n";
			} else {
				error_message = "~time_stats_updater(): extra measurements:\n";
				while (!measurements.empty()) {
					error_message += get_current_node_action_name() + '\n';
					pop_measurement();
				}
			}
			std::cerr << error_message << std::endl;
			throw std::logic_error(error_message);
		}
	}

	/*!
	 * \brief Represents single call measurement
	 */
	struct measurement {
		/*!
		 * \brief Initializes measurement with specified start time and pointer to previous node in call stack
		 * \param time Start time
		 * \param previous_node Pointer to previous node in call stack
		 */
		measurement(const time_point_t& time, p_node_t previous_node): start_time(time),
			previous_node(previous_node) {}

		/*!
		 * \brief Start time of the measurement
		 */
		time_point_t start_time;

		/*!
		 * \brief Pointer to previous node in call stack
		 */
		p_node_t previous_node;
	};

	/*!
	 * \brief Removes measurement from top of call stack and updates corresponding node in call-tree
	 * \param end_time End time of the measurement
	 */
	void pop_measurement(const time_point_t& end_time = std::chrono::system_clock::now()) {
		measurement previous_measurement = measurements.top();
		measurements.pop();
		time_stats_tree->get_time_stats_tree().inc_node_time(current_node, delta(previous_measurement.start_time, end_time));
		time_stats_tree->get_time_stats_tree().inc_node_calls_number(current_node);
		current_node = previous_measurement.previous_node;
		--depth;
	}

	/*!
	 * \brief Current position in call-tree
	 */
	p_node_t current_node;

	/*!
	 * \brief Call stack
	 */
	std::stack<measurement> measurements;

	/*!
	 * \brief Target call-tree
	 */
	concurrent_time_stats_tree_t* time_stats_tree;

	/*!
	 * \brief Current call stack depth
	 */
	size_t depth;

	/*!
	 * \brief Maximum monitored call stack depth
	 */
	size_t max_depth;

	/*!
	 * \brief Default monitored call stack depth
	 */
	static const size_t DEFAULT_DEPTH = -1;
};

template<typename TreeType>
class dummy_call_tree_updater_t : public call_tree_updater_t<TreeType> {
public:
	dummy_call_tree_updater_t() {}
	~dummy_call_tree_updater_t() {}

	void start(int) {}
	void stop(int) {}
};

/*!
 * \brief Auxiliary class for logging actions with variable place of stop time (branching/end of function/end of scope)
 */
template<typename TreeType>
class action_guard_base_t {
public:
	/*!
	 * \brief Initializes guard and starts action with \a action_code
	 * \param updater Updater whos start is called
	 * \param action_code Code of new action
	 */
	action_guard_base_t(call_tree_updater_t<TreeType> *updater, const int action_code):
		updater(updater), action_code(action_code), is_stopped(false) {
		if (updater) {
			updater->start(action_code);
		}
	}

	/*!
	 * \brief Stops action if it is not already stopped
	 */
	~action_guard_base_t() {
		if (!is_stopped && updater) {
			updater->stop(action_code);
		}
	}

	/*!
	 * \brief Allows to stop action manually
	 */
	void stop() {
		if (is_stopped) {
			throw std::logic_error("action " + updater->get_action_name(action_code) + " is already stopped");
		}

		if (updater) {
			updater->stop(action_code);
			is_stopped = true;
		}
	}

private:
	/*!
	 * \brief Updater whos start/stop are called
	 */
	call_tree_updater_t<TreeType> *updater;

	/*!
	 * \brief Action code of guarded action
	 */
	const int action_code;

	/*!
	 * \brief Shows if action is already stopped
	 */
	bool is_stopped;
};

typedef action_guard_base_t<call_tree_t> action_guard_t;

} // namespace react

#endif // UPDATER_HPP
<commit_msg>Compilation under gcc4.4 fixed<commit_after>/*
* 2013+ Copyright (c) Andrey Kashin <kashin.andrej@gmail.com>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*/

#ifndef UPDATER_HPP
#define UPDATER_HPP

#include <stack>
#include <stdexcept>

namespace react {

/*!
 * \brief Class for interactive building of call tree
 *
 *  Allows you to log actions in call-tree manner.
 */
template<typename TreeType>
class call_tree_updater_t {
public:
	typedef TreeType time_stats_tree_t;
	typedef concurrent_call_tree_t<TreeType> concurrent_time_stats_tree_t;

	/*!
	 * \brief Call tree node type
	 */
	typedef typename time_stats_tree_t::node_t node_t;

	/*!
	 * \brief Pointer to call tree node type
	 */
	typedef typename time_stats_tree_t::p_node_t p_node_t;

	/*!
	 * \brief Time point type
	 */
	typedef std::chrono::time_point<std::chrono::system_clock> time_point_t;

	/*!
	 * \brief Initializes updater without target tree
	 * \param max_depth Maximum monitored depth of call stack
	 */
	call_tree_updater_t(const size_t max_depth = DEFAULT_DEPTH):
		current_node(0), time_stats_tree(NULL), depth(0), max_depth(max_depth) {
		measurements.emplace(std::chrono::system_clock::now(), +time_stats_tree_t::NO_NODE);
	}

	/*!
	 * \brief Initializes updater with target tree
	 * \param time_stats_tree Tree used to monitor updates
	 * \param max_depth Maximum monitored depth of call stack
	 */
	call_tree_updater_t(concurrent_time_stats_tree_t &time_stats_tree,
			const size_t max_depth = DEFAULT_DEPTH):
		current_node(0), time_stats_tree(NULL), depth(0), max_depth(max_depth) {
		set_time_stats_tree(time_stats_tree);
		measurements.emplace(std::chrono::system_clock::now(), +time_stats_tree_t::NO_NODE);
	}

	/*!
	 * \brief Checks if all actions were correctly finished.
	 */
	virtual ~call_tree_updater_t() {
		check_for_extra_measurements();
	}

	/*!
	 * \brief Sets target tree for updates
	 * \param time_stats_tree Tree used to monitor updates
	 */
	void set_time_stats_tree(concurrent_time_stats_tree_t &time_stats_tree) {
		check_for_extra_measurements();
		current_node = time_stats_tree.get_time_stats_tree().root;
		this->time_stats_tree = &time_stats_tree;
		depth = 0;
	}

	/*!
	 * \brief Resets current call tree
	 */
	void reset_time_stats_tree() {
		check_for_extra_measurements();
		current_node = time_stats_tree_t::NO_NODE;
		this->time_stats_tree = NULL;
		depth = 0;
	}

	/*!
	 * \brief Checks whether tree for updates is set
	 * \return whether updater target tree was set
	 */
	bool has_time_stats_tree() const {
		return (time_stats_tree != NULL);
	}

	/*!
	 * \brief Starts new branch in tree with action \a action_code
	 * \param action_code Code of new action
	 */
	virtual void start(const int action_code) {
		start(action_code, std::chrono::system_clock::now());
	}

	/*!
	 * \brief Starts new branch in tree with action \a action_code and with specified start time
	 * \param action_code Code of new action
	 * \param start_time Action start time
	 */
	void start(const int action_code, const time_point_t& start_time) {
		++depth;
		if (get_depth() > max_depth) {
			return;
		}

		time_stats_tree->lock();
		p_node_t next_node = time_stats_tree->get_time_stats_tree().add_new_link_if_missing(current_node, action_code);
		time_stats_tree->unlock();

		measurements.emplace(start_time, current_node);
		current_node = next_node;
	}

	/*!
	 * \brief Stops last action. Updates total consumed time in call-tree.
	 * \param action_code Code of finished action
	 */
	virtual void stop(const int action_code) {
		if (get_depth() > max_depth) {
			--depth;
			return;
		}

		std::lock_guard<concurrent_time_stats_tree_t> guard(*time_stats_tree);

		int expected_code = time_stats_tree->get_time_stats_tree().get_node_action_code(current_node);
		if (expected_code != action_code) {
			std::string expected_action_name = get_action_name(expected_code);
			std::string found_action_name = get_action_name(action_code);
			throw std::logic_error("Stopping wrong action. Expected: " + expected_action_name + ", Found: " + found_action_name);
		}
		pop_measurement();
	}

	/*!
	 * \brief Sets max monitored call stack depth to \a max_depth
	 * \param max_depth Max monitored call stack depth
	 */
	void set_max_depth(const size_t max_depth) {
		if (depth != 0) {
			throw std::logic_error("can't change max_depth during update");
		}

		this->max_depth = max_depth;
	}

	/*!
	 * \brief Gets current call stack depth
	 * \return Current call stack depth
	 */
	size_t get_depth() const {
		return depth;
	}

	/*!
	 * \brief Returns name of action with \a action_code
	 * \return Name of action with \a action_code
	 */
	std::string get_action_name(int action_code) const {
		return time_stats_tree->get_time_stats_tree().get_actions_set().get_action_name(action_code);
	}

	/*!
	 * \brief Returns name of action in current node
	 * \return Current's node action name
	 */
	std::string get_current_node_action_name() const {
		return get_action_name(time_stats_tree->get_time_stats_tree().get_node_action_code(current_node));
	}

private:
	/*!
	 * \internal
	 *
	 * \brief Returns delta between two time_points
	 */
	template<class Period = std::chrono::microseconds>
	long long int delta(time_point_t& start, const time_point_t& end) const {
		return (std::chrono::duration_cast<Period> (end - start)).count();
	}

	/*!
	 * \internal
	 *
	 * \brief Assures that updater is empty
	 */
	void check_for_extra_measurements() {
		if (depth != 0) {
			std::string error_message;
			if (!time_stats_tree) {
				error_message = "~time_stats_updater(): extra measurements, tree is NULL\n";
			} else {
				error_message = "~time_stats_updater(): extra measurements:\n";
				while (!measurements.empty()) {
					error_message += get_current_node_action_name() + '\n';
					pop_measurement();
				}
			}
			std::cerr << error_message << std::endl;
			throw std::logic_error(error_message);
		}
	}

	/*!
	 * \brief Represents single call measurement
	 */
	struct measurement {
		/*!
		 * \brief Initializes measurement with specified start time and pointer to previous node in call stack
		 * \param time Start time
		 * \param previous_node Pointer to previous node in call stack
		 */
		measurement(const time_point_t& time, p_node_t previous_node): start_time(time),
			previous_node(previous_node) {}

		/*!
		 * \brief Start time of the measurement
		 */
		time_point_t start_time;

		/*!
		 * \brief Pointer to previous node in call stack
		 */
		p_node_t previous_node;
	};

	/*!
	 * \brief Removes measurement from top of call stack and updates corresponding node in call-tree
	 * \param end_time End time of the measurement
	 */
	void pop_measurement(const time_point_t& end_time = std::chrono::system_clock::now()) {
		measurement previous_measurement = measurements.top();
		measurements.pop();
		time_stats_tree->get_time_stats_tree().inc_node_time(current_node, delta(previous_measurement.start_time, end_time));
		time_stats_tree->get_time_stats_tree().inc_node_calls_number(current_node);
		current_node = previous_measurement.previous_node;
		--depth;
	}

	/*!
	 * \brief Current position in call-tree
	 */
	p_node_t current_node;

	/*!
	 * \brief Call stack
	 */
	std::stack<measurement> measurements;

	/*!
	 * \brief Target call-tree
	 */
	concurrent_time_stats_tree_t* time_stats_tree;

	/*!
	 * \brief Current call stack depth
	 */
	size_t depth;

	/*!
	 * \brief Maximum monitored call stack depth
	 */
	size_t max_depth;

	/*!
	 * \brief Default monitored call stack depth
	 */
	static const size_t DEFAULT_DEPTH = -1;
};

template<typename TreeType>
class dummy_call_tree_updater_t : public call_tree_updater_t<TreeType> {
public:
	dummy_call_tree_updater_t() {}
	~dummy_call_tree_updater_t() {}

	void start(int) {}
	void stop(int) {}
};

/*!
 * \brief Auxiliary class for logging actions with variable place of stop time (branching/end of function/end of scope)
 */
template<typename TreeType>
class action_guard_base_t {
public:
	/*!
	 * \brief Initializes guard and starts action with \a action_code
	 * \param updater Updater whos start is called
	 * \param action_code Code of new action
	 */
	action_guard_base_t(call_tree_updater_t<TreeType> *updater, const int action_code):
		updater(updater), action_code(action_code), is_stopped(false) {
		if (updater) {
			updater->start(action_code);
		}
	}

	/*!
	 * \brief Stops action if it is not already stopped
	 */
	~action_guard_base_t() {
		if (!is_stopped && updater) {
			updater->stop(action_code);
		}
	}

	/*!
	 * \brief Allows to stop action manually
	 */
	void stop() {
		if (is_stopped) {
			throw std::logic_error("action " + updater->get_action_name(action_code) + " is already stopped");
		}

		if (updater) {
			updater->stop(action_code);
			is_stopped = true;
		}
	}

private:
	/*!
	 * \brief Updater whos start/stop are called
	 */
	call_tree_updater_t<TreeType> *updater;

	/*!
	 * \brief Action code of guarded action
	 */
	const int action_code;

	/*!
	 * \brief Shows if action is already stopped
	 */
	bool is_stopped;
};

typedef action_guard_base_t<call_tree_t> action_guard_t;

} // namespace react

#endif // UPDATER_HPP
<|endoftext|>


<commit_before>/** @file
 *
 * @ingroup dspSoundFileLib
 *
 * @brief Provides a common interface to soundfile data
 *
 * @details This object provides a common set of attributes and methods for working with soundfiles at a specific filepath.
 * This allows us to access metadata and copy values in a common way without duplicating code. As with the rest of the
 * SoundfileLib, it relies on the third-party libsndfile library.@n
 * Be aware that attributes and metadata are cached when the setFilePath method is called in order to provide efficiency, but this may lead to problems if the file somehow changes after the method call.
 *
 * @authors Nathan Wolek
 *
 * @copyright Copyright © 2013 by Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSoundfile.h"

#define thisTTClass			TTSoundfile
#define thisTTClassName		"soundfile"
#define thisTTClassTags		"soundfile"

TT_AUDIO_CONSTRUCTOR,
mFilePath(kTTSymEmpty),
mNumChannels(0),
mSampleRate(0.0),
mLengthInSamples(0),
mLengthInSeconds(0.0),
mTitle(kTTSymEmpty),
mArtist(kTTSymEmpty),
mDate(kTTSymEmpty),
mAnnotation(kTTSymEmpty),
mSoundFile(NULL)
{
	// add the attributes and messages here
    addAttributeWithSetter(FilePath, kTypeSymbol);
    addAttribute(NumChannels, kTypeInt16);
        addAttributeProperty(NumChannels, readOnly, kTTBoolYes);
    // need to add the rest of these here...
    addAttribute(SampleRate, kTypeFloat64);
        addAttributeProperty(SampleRate, readOnly, kTTBoolYes);
    addAttribute(LengthInSamples, kTypeInt64);
        addAttributeProperty(LengthInSamples, readOnly, kTTBoolYes);
    addAttribute(LengthInSeconds, kTypeFloat64);
        addAttributeProperty(LengthInSeconds, readOnly, kTTBoolYes);
    addAttribute(Title, kTypeSymbol);
        addAttributeProperty(Title, readOnly, kTTBoolYes);
    addAttribute(Artist, kTypeSymbol);
        addAttributeProperty(Artist, readOnly, kTTBoolYes);
    addAttribute(Date, kTypeSymbol);
        addAttributeProperty(Date, readOnly, kTTBoolYes);
    addAttribute(Annotation, kTypeSymbol);
        addAttributeProperty(Annotation, readOnly, kTTBoolYes);

}

TTSoundfile::~TTSoundfile()
{
	// copied from TTSoundfilePlayer, confirm that it is needed
	if (mSoundFile)
		sf_close(mSoundFile);
}

TTErr TTSoundfile::setFilePath(const TTValue& newValue)
{
	TTSymbol	potentialFilePath = newValue;
	SNDFILE*	soundfile;
	const char*	textInfo;
#ifdef TT_PLATFORM_WIN
	// There is a bug in libsndfile on Windows where upon return from this function a runtime check fails
	// because the stack is corrupted around soundfileInfo when sf_open() is called.
	// We work around this by allocating some extra memory to absorb the overrun.
    // [tap - old comment from soundfileplayer]
	SF_INFO		soundfileInfo[2];
#else
	SF_INFO		soundfileInfo[1];
#endif

	memset(&soundfileInfo, 0, sizeof(SF_INFO));
	//soundfileInfo.format = 0;
	soundfile = sf_open(potentialFilePath.c_str(), SFM_READ, soundfileInfo);

	if (soundfile) { // if the filepath was valid

		// swap out the old for the new, but hold onto the old for a moment
		SNDFILE* oldSoundFile = mSoundFile;
		mSoundFile = soundfile;

		// if there was an old file, we can now close it
		if (oldSoundFile)
			sf_close(oldSoundFile);

		// copy the metadata to our local variable
		memcpy(&mSoundFileInfo, soundfileInfo, sizeof(SF_INFO));

		/* copy additional data to local variables */
        // filepath
		mFilePath = potentialFilePath;

        // number of channels
        mNumChannels = mSoundFileInfo.channels;

        // sample rate
        mSampleRate = mSoundFileInfo.samplerate;

        // duration in samples
		mLengthInSamples = mSoundFileInfo.frames;

        // duration in seconds
		mLengthInSeconds = mLengthInSamples / mSampleRate;

		// copy specific metadata pieces to separate TTSymbols
		// in transfer from player, made this little pattern into a macro
            #define SF_STRING_TO_TTSYMBOL(sf_info_piece, local_ttsymbol) \
                textInfo = sf_get_string(soundfile, sf_info_piece); \
                if (textInfo) { \
                    local_ttsymbol = TT(textInfo); \
                } \
                else local_ttsymbol = kTTSymEmpty;

		// title
		SF_STRING_TO_TTSYMBOL(SF_STR_TITLE, mTitle);
		// artist
		SF_STRING_TO_TTSYMBOL(SF_STR_ARTIST, mArtist);
		// date
		SF_STRING_TO_TTSYMBOL(SF_STR_DATE, mDate);
        // comment
		SF_STRING_TO_TTSYMBOL(SF_STR_COMMENT, mAnnotation);

		return kTTErrNone;

	} else { // if the filepath was invalid
		char errstr[256];
		sf_error_str(soundfile, errstr, 256);
		TTLogMessage("cannot open soundfile %s: %s", potentialFilePath.c_str(), errstr);

		return kTTErrInvalidValue;

	}

}

TTErr	TTSoundfile::peek(const TTColumnID frame, const TTRowID channel, TTSampleValue& value)
{
    TTSampleVector temp_value;
    sf_count_t seekInFrames;
    sf_count_t numSamplesRead;

    seekInFrames = sf_seek(mSoundFile, frame, SEEK_SET);

    if (seekInFrames == -1) {
        return kTTErrGeneric;
    }

    temp_value.resize(mNumChannels);

    numSamplesRead = sf_readf_double(mSoundFile, &temp_value[0], 1);

    if (numSamplesRead != 1) {
        return kTTErrGeneric;
    }

    value = temp_value[channel];
    return kTTErrNone;

}<commit_msg>using new filepath error code<commit_after>/** @file
 *
 * @ingroup dspSoundFileLib
 *
 * @brief Provides a common interface to soundfile data
 *
 * @details This object provides a common set of attributes and methods for working with soundfiles at a specific filepath.
 * This allows us to access metadata and copy values in a common way without duplicating code. As with the rest of the
 * SoundfileLib, it relies on the third-party libsndfile library.@n
 * Be aware that attributes and metadata are cached when the setFilePath method is called in order to provide efficiency, but this may lead to problems if the file somehow changes after the method call.
 *
 * @authors Nathan Wolek
 *
 * @copyright Copyright © 2013 by Nathan Wolek @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSoundfile.h"

#define thisTTClass			TTSoundfile
#define thisTTClassName		"soundfile"
#define thisTTClassTags		"soundfile"

TT_AUDIO_CONSTRUCTOR,
mFilePath(kTTSymEmpty),
mNumChannels(0),
mSampleRate(0.0),
mLengthInSamples(0),
mLengthInSeconds(0.0),
mTitle(kTTSymEmpty),
mArtist(kTTSymEmpty),
mDate(kTTSymEmpty),
mAnnotation(kTTSymEmpty),
mSoundFile(NULL)
{
	// add the attributes and messages here
    addAttributeWithSetter(FilePath, kTypeSymbol);
    addAttribute(NumChannels, kTypeInt16);
        addAttributeProperty(NumChannels, readOnly, kTTBoolYes);
    // need to add the rest of these here...
    addAttribute(SampleRate, kTypeFloat64);
        addAttributeProperty(SampleRate, readOnly, kTTBoolYes);
    addAttribute(LengthInSamples, kTypeInt64);
        addAttributeProperty(LengthInSamples, readOnly, kTTBoolYes);
    addAttribute(LengthInSeconds, kTypeFloat64);
        addAttributeProperty(LengthInSeconds, readOnly, kTTBoolYes);
    addAttribute(Title, kTypeSymbol);
        addAttributeProperty(Title, readOnly, kTTBoolYes);
    addAttribute(Artist, kTypeSymbol);
        addAttributeProperty(Artist, readOnly, kTTBoolYes);
    addAttribute(Date, kTypeSymbol);
        addAttributeProperty(Date, readOnly, kTTBoolYes);
    addAttribute(Annotation, kTypeSymbol);
        addAttributeProperty(Annotation, readOnly, kTTBoolYes);

}

TTSoundfile::~TTSoundfile()
{
	// copied from TTSoundfilePlayer, confirm that it is needed
	if (mSoundFile)
		sf_close(mSoundFile);
}

TTErr TTSoundfile::setFilePath(const TTValue& newValue)
{
	TTSymbol	potentialFilePath = newValue;
	SNDFILE*	soundfile;
	const char*	textInfo;
#ifdef TT_PLATFORM_WIN
	// There is a bug in libsndfile on Windows where upon return from this function a runtime check fails
	// because the stack is corrupted around soundfileInfo when sf_open() is called.
	// We work around this by allocating some extra memory to absorb the overrun.
    // [tap - old comment from soundfileplayer]
	SF_INFO		soundfileInfo[2];
#else
	SF_INFO		soundfileInfo[1];
#endif

	memset(&soundfileInfo, 0, sizeof(SF_INFO));
	//soundfileInfo.format = 0;
	soundfile = sf_open(potentialFilePath.c_str(), SFM_READ, soundfileInfo);

	if (soundfile) { // if the filepath was valid

		// swap out the old for the new, but hold onto the old for a moment
		SNDFILE* oldSoundFile = mSoundFile;
		mSoundFile = soundfile;

		// if there was an old file, we can now close it
		if (oldSoundFile)
			sf_close(oldSoundFile);

		// copy the metadata to our local variable
		memcpy(&mSoundFileInfo, soundfileInfo, sizeof(SF_INFO));

		/* copy additional data to local variables */
        // filepath
		mFilePath = potentialFilePath;

        // number of channels
        mNumChannels = mSoundFileInfo.channels;

        // sample rate
        mSampleRate = mSoundFileInfo.samplerate;

        // duration in samples
		mLengthInSamples = mSoundFileInfo.frames;

        // duration in seconds
		mLengthInSeconds = mLengthInSamples / mSampleRate;

		// copy specific metadata pieces to separate TTSymbols
		// in transfer from player, made this little pattern into a macro
            #define SF_STRING_TO_TTSYMBOL(sf_info_piece, local_ttsymbol) \
                textInfo = sf_get_string(soundfile, sf_info_piece); \
                if (textInfo) { \
                    local_ttsymbol = TT(textInfo); \
                } \
                else local_ttsymbol = kTTSymEmpty;

		// title
		SF_STRING_TO_TTSYMBOL(SF_STR_TITLE, mTitle);
		// artist
		SF_STRING_TO_TTSYMBOL(SF_STR_ARTIST, mArtist);
		// date
		SF_STRING_TO_TTSYMBOL(SF_STR_DATE, mDate);
        // comment
		SF_STRING_TO_TTSYMBOL(SF_STR_COMMENT, mAnnotation);

		return kTTErrNone;

	} else { // if the filepath was invalid
		char errstr[256];
		sf_error_str(soundfile, errstr, 256);
		TTLogMessage("cannot open soundfile %s: %s", potentialFilePath.c_str(), errstr);

		return kTTErrInvalidFilepath;

	}

}

TTErr	TTSoundfile::peek(const TTColumnID frame, const TTRowID channel, TTSampleValue& value)
{
    TTSampleVector temp_value;
    sf_count_t seekInFrames;
    sf_count_t numSamplesRead;

    seekInFrames = sf_seek(mSoundFile, frame, SEEK_SET);

    if (seekInFrames == -1) {
        return kTTErrGeneric;
    }

    temp_value.resize(mNumChannels);

    numSamplesRead = sf_readf_double(mSoundFile, &temp_value[0], 1);

    if (numSamplesRead != 1) {
        return kTTErrGeneric;
    }

    value = temp_value[channel];
    return kTTErrNone;

}<|endoftext|>